import React from 'react' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Card } from './card' describe('Card', () => { describe('Basic Rendering', () => { it('renders children', () => { render(Hello World) expect(screen.getByText('Hello World')).toBeInTheDocument() }) it('renders with custom styles', () => { const style = { backgroundColor: '#000' } render( Hello World , ) const card = screen.getByTestId('card') expect(card).toHaveStyle(style) }) it('renders with custom element using as prop', () => { render( Hello World , ) const card = screen.getByTestId('card') expect(card.tagName.toLowerCase()).toBe('section') }) it('renders with default div element', () => { render(Content) const card = screen.getByTestId('card') expect(card.tagName.toLowerCase()).toBe('div') }) it('applies custom classes', () => { render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveClass('custom-class') }) it('applies default shadow class', () => { render(Content) const card = screen.getByTestId('card') expect(card).toHaveClass('shadow-sm') }) }) describe('Compound Components', () => { it('renders Card.Title component', () => { render( Test Title , ) expect(screen.getByText('Test Title')).toBeInTheDocument() }) it('renders Card.Title as h3 by default', () => { render( Test Title , ) const title = screen.getByTestId('title') expect(title.tagName.toLowerCase()).toBe('h3') }) it('renders Card.Title with custom heading level', () => { render( Test Title , ) const title = screen.getByTestId('title') expect(title.tagName.toLowerCase()).toBe('h2') }) it('renders Card.Content component', () => { render( Test Content , ) expect(screen.getByText('Test Content')).toBeInTheDocument() }) it('renders Card.Content as article by default', () => { render( Test Content , ) const content = screen.getByTestId('content') expect(content.tagName.toLowerCase()).toBe('article') }) it('renders Card.Content with custom element', () => { render( Test Content , ) const content = screen.getByTestId('content') expect(content.tagName.toLowerCase()).toBe('div') }) it('renders Card.Footer component', () => { render( Test Footer , ) expect(screen.getByText('Test Footer')).toBeInTheDocument() }) it('renders Card.Footer with custom element', () => { render( Test Footer , ) const footer = screen.getByTestId('footer') expect(footer.tagName.toLowerCase()).toBe('footer') }) it('renders complete card structure', () => { render( Title Content Footer , ) expect(screen.getByText('Title')).toBeInTheDocument() expect(screen.getByText('Content')).toBeInTheDocument() expect(screen.getByText('Footer')).toBeInTheDocument() }) it('applies custom className to sub-components', () => { render( Title Content Footer , ) expect(screen.getByTestId('title')).toHaveClass('card-title', 'custom-title') expect(screen.getByTestId('content')).toHaveClass('card-content', 'custom-content') expect(screen.getByTestId('footer')).toHaveClass('card-footer', 'custom-footer') }) }) describe('Accessibility', () => { it('accepts aria-label prop', () => { render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('aria-label', 'Product card') }) it('accepts aria-labelledby prop', () => { render( Title , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('aria-labelledby', 'card-title') }) it('accepts aria-describedby prop', () => { render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('aria-describedby', 'card-desc') }) it('accepts custom role', () => { render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('role', 'article') }) }) describe('Interactive Card', () => { it('applies interactive attributes when interactive is true', () => { const handleClick = vi.fn() render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('role', 'button') expect(card).toHaveAttribute('tabIndex', '0') expect(card).toHaveAttribute('data-card', 'interactive') }) it('calls onClick when clicked', async () => { const handleClick = vi.fn() const user = userEvent.setup() render( Content , ) const card = screen.getByTestId('card') await user.click(card) expect(handleClick).toHaveBeenCalledTimes(1) }) it('calls onClick when Enter key is pressed', async () => { const handleClick = vi.fn() const user = userEvent.setup() render( Content , ) const card = screen.getByTestId('card') card.focus() await user.keyboard('{Enter}') expect(handleClick).toHaveBeenCalledTimes(1) }) it('calls onClick when Space key is pressed', async () => { const handleClick = vi.fn() const user = userEvent.setup() render( Content , ) const card = screen.getByTestId('card') card.focus() await user.keyboard(' ') expect(handleClick).toHaveBeenCalledTimes(1) }) it('does not call onClick for other keys', async () => { const handleClick = vi.fn() const user = userEvent.setup() render( Content , ) const card = screen.getByTestId('card') card.focus() await user.keyboard('a') expect(handleClick).not.toHaveBeenCalled() }) it('allows custom tabIndex', () => { render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('tabIndex', '-1') }) it('allows custom role override for interactive cards', () => { render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('role', 'link') }) it('is keyboard focusable when interactive', () => { render( Content , ) const card = screen.getByTestId('card') expect(card).toHaveAttribute('tabIndex', '0') }) }) describe('Non-Interactive with onClick', () => { it('allows onClick without interactive prop', async () => { const handleClick = vi.fn() const user = userEvent.setup() render( Content , ) const card = screen.getByTestId('card') await user.click(card) expect(handleClick).toHaveBeenCalledTimes(1) }) it('does not add role="button" without interactive', () => { const handleClick = vi.fn() render( Content , ) const card = screen.getByTestId('card') expect(card).not.toHaveAttribute('role') }) it('does not add tabIndex without interactive', () => { const handleClick = vi.fn() render( Content , ) const card = screen.getByTestId('card') expect(card).not.toHaveAttribute('tabIndex') }) }) describe('Display Names', () => { it('has correct display name for Card', () => { expect(Card.displayName).toBe('Card') }) it('has correct display name for Card.Title', () => { expect(Card.Title.displayName).toBe('Card.Title') }) it('has correct display name for Card.Content', () => { expect(Card.Content.displayName).toBe('Card.Content') }) it('has correct display name for Card.Footer', () => { expect(Card.Footer.displayName).toBe('Card.Footer') }) }) })