import React from 'react'
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import { Skeleton, SkeletonText, SkeletonAvatar, SkeletonCard } from '../skeleton'
describe('Skeleton Components', () => {
describe('Skeleton Component', () => {
it('renders correctly with default props', () => {
render()
const skeleton = screen.getByTestId('skeleton')
expect(skeleton).toBeInTheDocument()
expect(skeleton).toHaveClass('animate-pulse')
expect(skeleton).toHaveClass('rounded-md')
expect(skeleton).toHaveClass('bg-muted')
})
it('applies custom className', () => {
render()
const skeleton = screen.getByTestId('skeleton')
expect(skeleton).toHaveClass('custom-skeleton')
})
it('forwards ref correctly', () => {
const ref = React.createRef()
render()
expect(ref.current).toBeInstanceOf(HTMLDivElement)
})
it('applies custom dimensions', () => {
render()
const skeleton = screen.getByTestId('skeleton')
expect(skeleton).toHaveStyle({ height: '100px', width: '200px' })
})
it('renders primary variant', () => {
render()
const skeleton = screen.getByTestId('skeleton')
expect(skeleton).toHaveClass('bg-primary/10')
})
it('renders circle shape', () => {
render()
const skeleton = screen.getByTestId('skeleton')
expect(skeleton).toHaveClass('rounded-full')
})
it('shows children when loaded', () => {
render(Content)
expect(screen.getByText('Content')).toBeInTheDocument()
})
it('shows skeleton when not loaded', () => {
render(Content)
const skeleton = screen.getByTestId('skeleton')
expect(skeleton).toHaveClass('animate-pulse')
expect(screen.queryByText('Content')).not.toBeInTheDocument()
})
it('maintains displayName', () => {
expect(Skeleton.displayName).toBe('Skeleton')
})
})
describe('SkeletonText Component', () => {
it('renders correctly with default props', () => {
render()
const container = screen.getByTestId('skeleton-text')
expect(container).toBeInTheDocument()
expect(container).toHaveClass('flex')
const skeletons = container.querySelectorAll('.animate-pulse')
expect(skeletons).toHaveLength(3) // default lines
})
it('renders custom number of lines', () => {
render()
const container = screen.getByTestId('skeleton-text')
const skeletons = container.querySelectorAll('.animate-pulse')
expect(skeletons).toHaveLength(5)
})
it('applies custom line height', () => {
render()
const container = screen.getByTestId('skeleton-text')
const firstLine = container.querySelector('.animate-pulse')
expect(firstLine).toHaveStyle({ height: '1rem' })
})
it('applies custom spacing', () => {
render()
const container = screen.getByTestId('skeleton-text')
expect(container).toHaveStyle({ gap: '1rem' })
})
it('forwards ref correctly', () => {
const ref = React.createRef()
render()
expect(ref.current).toBeInstanceOf(HTMLDivElement)
})
it('maintains displayName', () => {
expect(SkeletonText.displayName).toBe('SkeletonText')
})
})
describe('SkeletonAvatar Component', () => {
it('renders correctly with default props', () => {
render()
const avatar = screen.getByTestId('skeleton-avatar')
expect(avatar).toBeInTheDocument()
expect(avatar).toHaveClass('animate-pulse')
expect(avatar).toHaveClass('rounded-full')
expect(avatar).toHaveClass('shrink-0')
expect(avatar).toHaveStyle({ height: '2.5rem', width: '2.5rem' })
})
it('applies custom size', () => {
render()
const avatar = screen.getByTestId('skeleton-avatar')
expect(avatar).toHaveStyle({ height: '3rem', width: '3rem' })
})
it('applies custom size as number', () => {
render()
const avatar = screen.getByTestId('skeleton-avatar')
expect(avatar).toHaveStyle({ height: '48px', width: '48px' })
})
it('forwards ref correctly', () => {
const ref = React.createRef()
render()
expect(ref.current).toBeInstanceOf(HTMLDivElement)
})
it('renders with custom variant', () => {
render()
const avatar = screen.getByTestId('skeleton-avatar')
expect(avatar).toHaveClass('bg-primary/10')
})
it('maintains displayName', () => {
expect(SkeletonAvatar.displayName).toBe('SkeletonAvatar')
})
})
describe('SkeletonCard Component', () => {
it('renders correctly with default props', () => {
render()
const card = screen.getByTestId('skeleton-card')
expect(card).toBeInTheDocument()
expect(card).toHaveClass('overflow-hidden')
expect(card).toHaveClass('rounded-md')
expect(card).toHaveClass('border')
expect(card).toHaveClass('bg-background')
expect(card).toHaveClass('p-4')
})
it('shows header by default', () => {
render()
const card = screen.getByTestId('skeleton-card')
// Check for avatar in header
const avatar = card.querySelector('.shrink-0.rounded-full')
expect(avatar).toBeInTheDocument()
})
it('hides header when showHeader is false', () => {
render()
const card = screen.getByTestId('skeleton-card')
// Avatar should not be present
const avatar = card.querySelector('.shrink-0.rounded-full')
expect(avatar).not.toBeInTheDocument()
})
it('renders custom number of content lines', () => {
render()
const card = screen.getByTestId('skeleton-card')
const textContainer = card.querySelector('.flex.flex-col')
expect(textContainer).toBeInTheDocument()
const contentLines = textContainer?.querySelectorAll('.animate-pulse')
expect(contentLines).toHaveLength(5)
})
it('shows footer by default', () => {
render()
const card = screen.getByTestId('skeleton-card')
const footer = card.querySelector('.border-t')
expect(footer).toBeInTheDocument()
})
it('hides footer when showFooter is false', () => {
render()
const card = screen.getByTestId('skeleton-card')
const footer = card.querySelector('.border-t')
expect(footer).not.toBeInTheDocument()
})
it('forwards ref correctly', () => {
const ref = React.createRef()
render()
expect(ref.current).toBeInstanceOf(HTMLDivElement)
})
it('maintains displayName', () => {
expect(SkeletonCard.displayName).toBe('SkeletonCard')
})
})
describe('Edge Cases', () => {
it('handles zero lines in SkeletonText', () => {
render()
const container = screen.getByTestId('skeleton-text')
const skeletons = container.querySelectorAll('.animate-pulse')
expect(skeletons).toHaveLength(0)
})
it('handles all sections disabled in SkeletonCard', () => {
render(
)
const card = screen.getByTestId('skeleton-card')
// No header avatar
const avatar = card.querySelector('.shrink-0.rounded-full')
expect(avatar).not.toBeInTheDocument()
// No footer
const footer = card.querySelector('.border-t')
expect(footer).not.toBeInTheDocument()
// Only content lines
const textContainer = card.querySelector('.flex.flex-col')
const contentLines = textContainer?.querySelectorAll('.animate-pulse')
expect(contentLines).toHaveLength(1)
})
it('passes through HTML attributes', () => {
render()
const skeleton = screen.getByTestId('skeleton-test')
expect(skeleton).toHaveAttribute('id', 'skeleton-1')
})
})
})