import * as React from 'react' import { render } from '@testing-library/react' import { describe, expect, it } from 'vitest' import { axe } from 'vitest-axe' import { Button } from '../button/button' import { ButtonGroup } from './button-group' describe('ButtonGroup', () => { it('renders a data-slot wrapper with role=group and default horizontal classes', () => { const { container } = render( , ) const group = container.querySelector('[data-slot="button-group"]') as HTMLElement expect(group).not.toBeNull() expect(group.getAttribute('role')).toBe('group') expect(group.className).toContain('flex') expect(group.className).toContain('w-fit') expect(group.className).toContain('items-stretch') expect(group.className).toContain('[&>*:not(:first-of-type)]:rounded-s-none') expect(group.className).toContain('[&>*:not(:last-of-type)]:rounded-e-none') }) it('switches to vertical classes when orientation="vertical"', () => { const { container } = render( , ) const group = container.querySelector('[data-slot="button-group"]') as HTMLElement expect(group.className).toContain('flex-col') expect(group.className).toContain('[&>*:not(:first-of-type)]:rounded-t-none') expect(group.className).toContain('[&>*:not(:last-of-type)]:rounded-b-none') expect(group.className).not.toContain('rounded-l-none') expect(group.className).not.toContain('rounded-r-none') }) it.each(['primary-outline', 'outline', 'light'] as const)( 'uses negative -space-x for outlined variant "%s"', (variant) => { const { container } = render( , ) const group = container.querySelector('[data-slot="button-group"]') as HTMLElement expect(group.className).toContain('-space-x-(--border-width)') expect(group.className).not.toContain(' space-x-(--border-width)') }, ) it('uses positive space-x for filled variants', () => { const { container } = render( , ) const group = container.querySelector('[data-slot="button-group"]') as HTMLElement expect(group.className).toContain('space-x-(--border-width)') expect(group.className).not.toContain('-space-x-(--border-width)') }) it('uses negative -space-y for outlined variant in vertical orientation', () => { const { container } = render( , ) const group = container.querySelector('[data-slot="button-group"]') as HTMLElement expect(group.className).toContain('-space-y-(--border-width)') }) it('uses positive space-y for filled variants in vertical orientation', () => { const { container } = render( , ) const group = container.querySelector('[data-slot="button-group"]') as HTMLElement expect(group.className).toContain('space-y-(--border-width)') expect(group.className).not.toContain('-space-y-(--border-width)') }) it('propagates size to child Buttons', () => { const { container } = render( , ) const button = container.querySelector('[data-slot="button"]') as HTMLElement expect(button.className).toContain('h-12') }) it('propagates variant to child Buttons', () => { const { container } = render( , ) const button = container.querySelector('[data-testid="btn"]') as HTMLElement // outline variant adds the border-line class expect(button.className).toContain('before:border') }) it('lets an explicit prop on an inner Button override the group default', () => { const { container } = render( , ) const overridden = container.querySelector('[data-testid="overridden"]') as HTMLElement expect(overridden.className).toContain('h-8') expect(overridden.className).not.toContain('h-12') const inherits = container.querySelector('[data-testid="inherits"]') as HTMLElement expect(inherits.className).toContain('h-12') }) it('merges caller className on the wrapper', () => { const { container } = render( , ) const group = container.querySelector('[data-slot="button-group"]') as HTMLElement expect(group.className).toContain('my-group') }) it('propagates size/variant through a wrapping component (context, not direct child)', () => { function Wrapper({ children }: { children: React.ReactNode }) { return {children} } const { container } = render( , ) const nested = container.querySelector('[data-testid="nested"]') as HTMLElement expect(nested.className).toContain('h-12') expect(nested.className).toContain('before:border') }) it('group `disabled` disables every child Button', () => { const { container } = render( , ) const a = container.querySelector('[data-testid="a"]') as HTMLButtonElement const b = container.querySelector('[data-testid="b"]') as HTMLButtonElement expect(a.disabled).toBe(true) expect(b.disabled).toBe(true) }) it('per-Button `disabled` adds to (does not override) the group state', () => { const { container } = render( , ) const own = container.querySelector('[data-testid="own"]') as HTMLButtonElement const other = container.querySelector('[data-testid="other"]') as HTMLButtonElement expect(own.disabled).toBe(true) expect(other.disabled).toBe(false) }) it('group disabled wins over a child setting disabled={false}', () => { const { container } = render( , ) const b = container.querySelector('[data-testid="b"]') as HTMLButtonElement expect(b.disabled).toBe(true) }) it('Button outside any group keeps its defaults (variant=primary, size=md, not disabled)', () => { const { container } = render() const btn = container.querySelector('[data-testid="solo"]') as HTMLButtonElement expect(btn.disabled).toBe(false) expect(btn.className).toContain('h-10') // md }) it('has no accessibility violations', async () => { const { container } = render( , ) expect(await axe(container)).toHaveNoViolations() }) })