Skip to content

Conversation

@Arnab-Mandal1
Copy link
Collaborator

@Arnab-Mandal1 Arnab-Mandal1 commented Nov 9, 2025

Description

This pull request introduces a new, reusable Badge component to the UI library. This component is designed to display short pieces of information, such as tags or statuses, with styling based on DaisyUI variants.

Key Features:

  • Displays customizable text content.
  • Supports primary, secondary, accent, and ghost variants for different visual styles.
  • Includes an optional removable prop that, when true, displays a close button and triggers an onRemove callback.
  • The color prop is intentionally ignored in favor of the variant prop to align with DaisyUI's class-based styling system.
  • Handles whitespace in text content gracefully using whitespace-pre-wrap.

To ensure quality and document usage, this PR also includes:

  • Comprehensive Tests: A full test suite for the Badge component using Vitest and React Testing Library, covering rendering, variants, functionality, accessibility, and edge cases.
  • Storybook Stories: A set of stories to visually test and document the component's different states and props.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🧪 New tests (adding new tests for existing or new features)
  • 📚 Documentation (changes to Storybook or JSDoc)

How Has This Been Tested?

The Badge component has been thoroughly tested to ensure its reliability and correctness:

  • Unit & Integration Tests: A comprehensive test suite has been added in Badge.test.tsx with 100% coverage of all logic, including:
    • Correct rendering based on props.
    • Variant class application.
    • Conditional rendering of the remove button.
    • onRemove event handler functionality.
    • Accessibility checks for roles and keyboard focus.
    • Graceful handling of edge cases like empty text, special characters, and undefined callbacks.
  • Visual Testing: Storybook stories have been created in Badge.stories.tsx to allow for visual regression testing and to serve as living documentation for the component's appearance and behavior across different props.

All tests are passing in the CI pipeline.

Checklist

  • My code follows the style guidelines of this project.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have added corresponding stories to Storybook.

Summary by CodeRabbit

  • Bug Fixes

    • Badge text now preserves whitespace (leading/trailing spaces) and wraps correctly.
  • Tests

    • Added comprehensive Badge tests covering rendering, variants, colors, removable behavior, accessibility, and edge cases.
  • Documentation

    • Added multiple Badge examples demonstrating variants, colors, removable behavior, text content, and whitespace handling.

run all the test cases , fixes the error and delete errornious test cases
@Arnab-Mandal1 Arnab-Mandal1 requested a review from dbc2201 November 9, 2025 13:23
@Arnab-Mandal1 Arnab-Mandal1 self-assigned this Nov 9, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 9, 2025

Walkthrough

Added six Storybook stories for Badge, a comprehensive test suite exercising rendering, variants, removable behavior, accessibility, and edge cases, and applied whitespace-pre-wrap to the Badge text span to preserve whitespace.

Changes

Cohort / File(s) Summary
Badge stories
src/components/ui/Badge/Badge.stories.tsx
Added six new Storybook exports exercising rendering, variants, color prop, removable behavior, text content, and whitespace edge cases; minor formatting adjustments around the Default export.
Badge tests
src/components/ui/Badge/Badge.test.tsx
Added comprehensive test suite covering default/custom props, text rendering, DOM structure, removable button behavior and accessibility, variant/color precedence, edge cases (empty, numeric, long, emoji, whitespace), and interaction (clicks, rapid clicks, undefined onRemove).
Badge implementation
src/components/ui/Badge/Badge.tsx
Added className="whitespace-pre-wrap" to the inner <span> that renders props.text to preserve and wrap whitespace.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay attention to test coverage quality and potential false positives/fragile selectors in Badge.test.tsx.
  • Confirm story args and naming follow project Storybook conventions in Badge.stories.tsx.
  • Verify the whitespace-pre-wrap class doesn't conflict with existing styling or layout in Badge.tsx.

Possibly related PRs

Suggested labels

documentation

Poem

🐰 I hopped in code to mend a gap,

Badges gleam with whitespace wrapped,
Stories bloom and tests applaud,
A tiny fix, and joy unwrapped ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the PR's main contribution: adding a new Badge component with accompanying tests and Storybook stories.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch badge-test-done

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: 2

Caution

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

⚠️ Outside diff range comments (1)
src/components/ui/Badge/Badge.tsx (1)

12-14: Update BadgeProps interface to reflect optional props with defaults.

The type contract mismatch is confirmed. BadgeProps declares variant and removable as required, but the component implementation treats them as optional with default values via ?? operators (lines 13-14 of Badge.tsx). This contradicts the type contract.

Update src/components/ui/Badge/BadgeProps.ts to make these props optional:

export interface BadgeProps {
  text: string,
  color: string,
  variant?: 'primary' | 'secondary' | 'accent' | 'ghost',
  removable?: boolean,
  onRemove?: () => void
}
🧹 Nitpick comments (4)
src/components/ui/Badge/Badge.test.tsx (2)

155-176: Consider simpler approach for undefined prop testing.

The tests use delete (props as BadgeProps).onRemove to test missing callbacks. Since onRemove is already optional in the interface, you can simply pass undefined or omit it from the object for cleaner, more idiomatic code.

  it('renders without onRemove callback when removable is true', () => {
-   const props = makeProps({ removable: true });
-   delete (props as BadgeProps).onRemove;
+   const props = makeProps({ removable: true, onRemove: undefined });

    expect(() => {
      render(<Badge {...props} />);
    }).not.toThrow();

298-331: Consider testing for accessible button labels.

While the accessibility tests verify button presence and keyboard focus, they don't validate screen reader experience. The remove button currently only contains "✕" without an aria-label, which may not be sufficiently descriptive for screen reader users.

Consider adding a test to verify accessible labeling:

it('remove button has accessible label for screen readers', () => {
  const props = makeProps({ removable: true, onRemove: vi.fn() });
  render(<Badge {...props} />);

  const removeButton = screen.getByRole('button');
  expect(removeButton).toHaveAccessibleName(/remove/i);
});

Then update the Badge component to include proper labeling:

  {removable && (
-   <button onClick={props.onRemove} className="btn btn-ghost btn-xs">
+   <button onClick={props.onRemove} className="btn btn-ghost btn-xs" aria-label="Remove badge">
      ✕
    </button>
  )}
src/components/ui/Badge/Badge.stories.tsx (2)

21-73: Remove unused color prop from stories.

The Badge component explicitly ignores the color prop in favor of variant (as noted in Badge.tsx lines 15-16). Including color in the story args is misleading and adds no value.

Remove the color prop from all story definitions:

  export const BadgeComponentRenderingPass: Story = {
    args: {
      text: "sale 50% off",
-     color: "color",
      variant: "primary",
      removable: false
    }
  };

Apply this change to all stories that include the color prop.


13-19: Make Default story more representative.

The Default story is missing variant and removable props, relying on component defaults. For better documentation, explicitly show all key props.

  export const Default: Story = {
    args: {
      text: "text",
-     color: "color",
+     variant: "primary",
+     removable: false,
-     onRemove: () => {}
    }
  };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c40bb0e and 6b5f456.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • src/components/ui/Badge/Badge.stories.tsx (1 hunks)
  • src/components/ui/Badge/Badge.test.tsx (1 hunks)
  • src/components/ui/Badge/Badge.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/ui/Badge/Badge.test.tsx (2)
src/components/ui/Badge/BadgeProps.ts (1)
  • BadgeProps (1-7)
src/components/ui/Badge/Badge.tsx (1)
  • Badge (12-31)
🔇 Additional comments (4)
src/components/ui/Badge/Badge.tsx (1)

25-25: LGTM! Appropriate styling for text preservation.

The whitespace-pre-wrap class correctly preserves whitespace while allowing text to wrap, which aligns with the test coverage and the "WhitespaceErrorSolved" story.

src/components/ui/Badge/Badge.test.tsx (3)

1-6: LGTM! Clean test setup.

All necessary testing utilities are correctly imported.


9-15: LGTM! Well-designed test helper.

The makeProps helper provides sensible defaults and allows flexible overrides via the spread operator.


369-374: LGTM! Good edge case coverage.

The whitespace test correctly validates the whitespace-pre-wrap behavior added to the component.

correct the erroneous test code
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

♻️ Duplicate comments (1)
src/components/ui/Badge/Badge.test.tsx (1)

279-295: Potential DOM pollution in loop test.

Rendering multiple Badge components in a loop without unmounting previous instances may cause DOM pollution. The screen.getByRole('button') query could match buttons from earlier iterations if cleanup doesn't occur between renders.

Consider either:

  1. Creating separate test cases for each variant
  2. Using unmount() between iterations
  3. Using within() to scope queries to the specific container
  variants.forEach((variant) => {
    const props = makeProps({ variant, removable: true, onRemove: vi.fn() });
-   const { container } = render(<Badge {...props} />);
+   const { container, unmount } = render(<Badge {...props} />);

    const badge = container.firstElementChild as HTMLElement;
    expect(badge).toHaveClass(`badge-${variant}`);
-   expect(screen.getByRole('button')).toBeInTheDocument();
+   expect(within(container).getByRole('button')).toBeInTheDocument();
+   unmount();
  });
🧹 Nitpick comments (5)
src/components/ui/Badge/Badge.test.tsx (5)

103-120: Consider consolidating redundant color tests.

Both tests verify the same behavior (color prop is ignored in favor of variant) with different values. One test would suffice, reducing maintenance overhead.

Example consolidation:

 describe('Color Prop', () => {
   it('ignores color prop in favor of variant', () => {
     const props = makeProps({ color: 'red', variant: 'primary' });
     const { container } = render(<Badge {...props} />);

     const badge = container.firstElementChild as HTMLElement;
     expect(badge).toHaveClass('badge-primary');
     expect(badge).not.toHaveClass('red');
   });
-
-  it('variant takes precedence over color', () => {
-    const props = makeProps({ color: 'blue', variant: 'accent' });
-    const { container } = render(<Badge {...props} />);
-
-    const badge = container.firstElementChild as HTMLElement;
-    expect(badge).toHaveClass('badge-accent');
-  });
 });

155-176: Consider cleaner approach for testing undefined onRemove.

Using delete to remove the property works but is less idiomatic. You can achieve the same result by explicitly passing onRemove: undefined in makeProps.

Apply this diff:

  it('renders without onRemove callback when removable is true', () => {
-   const props = makeProps({ removable: true });
-   delete (props as BadgeProps).onRemove;
+   const props = makeProps({ removable: true, onRemove: undefined });

    expect(() => {
      render(<Badge {...props} />);
    }).not.toThrow();

    const removeButton = screen.getByRole('button');
    expect(removeButton).toBeInTheDocument();
  });

  it('does not throw error when clicking remove button without onRemove callback', () => {
-   const props = makeProps({ removable: true });
-   delete (props as BadgeProps).onRemove;
+   const props = makeProps({ removable: true, onRemove: undefined });
    render(<Badge {...props} />);

    const removeButton = screen.getByRole('button');
    expect(() => {
      fireEvent.click(removeButton);
    }).not.toThrow();
  });

369-374: Whitespace test doesn't verify whitespace preservation.

The test uses a partial regex match /Spaced/ which will pass regardless of whether the whitespace-pre-wrap class actually preserves leading/trailing whitespace. Since the component explicitly applies this class, the test should verify that whitespace is preserved in the rendered output.

Apply this diff to properly test whitespace preservation:

  it('handles whitespace in text', () => {
    const props = makeProps({ text: '  Spaced  ' });
-   render(<Badge {...props} />);
+   const { container } = render(<Badge {...props} />);

-   expect(screen.getByText(/Spaced/)).toBeInTheDocument();
+   const span = container.querySelector('span');
+   expect(span).toHaveTextContent('  Spaced  ');
+   expect(span).toHaveClass('whitespace-pre-wrap');
  });

356-367: Consider removing redundant rapid clicks test.

This test is functionally identical to the "calls onRemove multiple times" test at lines 134-145. Both verify that onRemove is called the correct number of times on multiple clicks. The difference in click count (10 vs 3) doesn't add meaningful coverage.


377-393: Consider removing redundant default value tests.

Both tests duplicate coverage from earlier sections:

  • Lines 378-384 duplicate the "renders with default props" test (lines 18-25)
  • Lines 386-392 duplicate the "does not render remove button when removable is false" test (lines 43-49)

While documenting default behavior is valuable, these specific assertions are already covered.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b5f456 and 1b2ebf5.

📒 Files selected for processing (1)
  • src/components/ui/Badge/Badge.test.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/ui/Badge/Badge.test.tsx (2)
src/components/ui/Badge/BadgeProps.ts (1)
  • BadgeProps (1-7)
src/components/ui/Badge/Badge.tsx (1)
  • Badge (12-31)
🔇 Additional comments (6)
src/components/ui/Badge/Badge.test.tsx (6)

1-15: LGTM! Clean test setup.

The imports and makeProps helper follow testing best practices. The factory function with overrides makes tests readable and maintainable.


17-59: LGTM! Comprehensive rendering tests.

The rendering tests appropriately cover default props, custom text, and conditional remove button rendering. Good use of queryByRole for negative assertions.


61-101: LGTM! Variant tests are thorough.

All variant options are properly tested. The explicit test for base classes (lines 94-100) serves as useful documentation even though similar assertions appear elsewhere.


179-219: LGTM! Text content tests cover various scenarios.

The tests appropriately handle edge cases including empty strings, numeric values, long text, special characters, and emoji.


221-259: LGTM! DOM structure tests are well-designed.

The tests verify the component's DOM hierarchy and element relationships correctly.


298-331: LGTM! Good accessibility coverage.

The tests appropriately verify keyboard accessibility, focus behavior, and semantic HTML roles.

@dbc2201 dbc2201 merged commit a82d023 into main Nov 12, 2025
1 check passed
@dbc2201 dbc2201 deleted the badge-test-done branch November 12, 2025 11:27
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.

3 participants