jest.mock('../../../src/renderer/lib/utils', () => ({ cn: (...classes: string[]) => classes.join(' '), })); jest.mock('@radix-ui/react-avatar', () => ({ Root: ({ children, className, ...props }: any) => React.createElement( 'div', { 'data-testid': 'avatar-root', className, ...props }, children ), Image: ({ className, ...props }: any) => React.createElement('img', { 'data-testid': 'avatar-image', className, ...props, }), Fallback: ({ children, className, ...props }: any) => React.createElement( 'div', { 'data-testid': 'avatar-fallback', className, ...props }, children ), })); import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { Avatar, AvatarImage, AvatarFallback, } from '../../../src/renderer/components/ui/avatar'; describe('Avatar Component', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('Avatar Root', () => { test('renders with default props', () => { render(); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toBeInTheDocument(); expect(avatar).toHaveAttribute('data-slot', 'avatar'); expect(avatar).toHaveClass('relative'); expect(avatar).toHaveClass('flex'); expect(avatar).toHaveClass('size-8'); expect(avatar).toHaveClass('shrink-0'); expect(avatar).toHaveClass('overflow-hidden'); expect(avatar).toHaveClass('rounded-full'); }); test('applies custom className', () => { render(); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toHaveClass('custom-class'); }); test('forwards additional props', () => { render(); expect(screen.getByTestId('custom-avatar')).toBeInTheDocument(); }); test('has correct accessibility attributes', () => { render(); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toHaveAttribute('role', 'img'); expect(avatar).toHaveAttribute('aria-label', 'User avatar'); }); }); describe('AvatarImage', () => { test('renders with src and alt', () => { render( ); const image = screen.getByTestId('avatar-image'); expect(image).toBeInTheDocument(); expect(image).toHaveAttribute('src', 'https://example.com/avatar.jpg'); expect(image).toHaveAttribute('alt', 'User Avatar'); expect(image).toHaveClass('aspect-square'); expect(image).toHaveClass('size-full'); }); test('applies custom className', () => { render( ); const image = screen.getByTestId('avatar-image'); expect(image).toHaveClass('custom-image'); }); test('forwards additional props', () => { render( ); const image = screen.getByTestId('avatar-image'); expect(image).toHaveAttribute('loading', 'lazy'); }); test('handles missing src gracefully', () => { render( ); const image = screen.getByTestId('avatar-image'); expect(image).toBeInTheDocument(); expect(image).toHaveAttribute('alt', 'Fallback'); }); }); describe('AvatarFallback', () => { test('renders with children', () => { render( JD ); const fallback = screen.getByTestId('avatar-fallback'); expect(fallback).toBeInTheDocument(); expect(fallback).toHaveTextContent('JD'); expect(fallback).toHaveClass('bg-muted'); expect(fallback).toHaveClass('flex'); expect(fallback).toHaveClass('size-full'); expect(fallback).toHaveClass('items-center'); expect(fallback).toHaveClass('justify-center'); expect(fallback).toHaveClass('rounded-full'); }); test('applies custom className', () => { render( AB ); const fallback = screen.getByTestId('avatar-fallback'); expect(fallback).toHaveClass('custom-fallback'); }); test('handles complex children', () => { render( User Name ); const fallback = screen.getByTestId('avatar-fallback'); expect(fallback).toHaveTextContent('User'); expect(fallback).toHaveTextContent('Name'); }); test('renders with emoji', () => { render( 👤 ); const fallback = screen.getByTestId('avatar-fallback'); expect(fallback).toHaveTextContent('👤'); }); test('forwards additional props', () => { render( Test ); expect(screen.getByTestId('custom-fallback')).toBeInTheDocument(); }); }); describe('Complete Avatar Usage', () => { test('renders with image and fallback', () => { render( UN ); expect(screen.getByTestId('avatar-root')).toBeInTheDocument(); expect(screen.getByTestId('avatar-image')).toBeInTheDocument(); expect(screen.getByTestId('avatar-fallback')).toBeInTheDocument(); }); test('renders fallback when image fails', () => { render( BF ); expect(screen.getByTestId('avatar-image')).toBeInTheDocument(); expect(screen.getByTestId('avatar-fallback')).toBeInTheDocument(); expect(screen.getByText('BF')).toBeInTheDocument(); }); test('renders only fallback when no image', () => { render( OF ); expect(screen.queryByTestId('avatar-image')).not.toBeInTheDocument(); expect(screen.getByTestId('avatar-fallback')).toBeInTheDocument(); expect(screen.getByText('OF')).toBeInTheDocument(); }); test('renders only image when no fallback', () => { render( ); expect(screen.getByTestId('avatar-image')).toBeInTheDocument(); expect(screen.queryByTestId('avatar-fallback')).not.toBeInTheDocument(); }); }); describe('Data Attributes', () => { test('Avatar has correct data-slot', () => { render(); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toHaveAttribute('data-slot', 'avatar'); }); test('AvatarImage has correct data-slot', () => { render( ); const image = screen.getByTestId('avatar-image'); expect(image).toHaveAttribute('data-slot', 'avatar-image'); }); test('AvatarFallback has correct data-slot', () => { render( Test ); const fallback = screen.getByTestId('avatar-fallback'); expect(fallback).toHaveAttribute('data-slot', 'avatar-fallback'); }); }); describe('Styling and Classes', () => { test('Avatar applies base classes correctly', () => { render(); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toHaveClass( 'relative', 'flex', 'size-8', 'shrink-0', 'overflow-hidden', 'rounded-full' ); }); test('AvatarImage applies base classes correctly', () => { render( ); const image = screen.getByTestId('avatar-image'); expect(image).toHaveClass('aspect-square', 'size-full'); }); test('AvatarFallback applies base classes correctly', () => { render( Test ); const fallback = screen.getByTestId('avatar-fallback'); expect(fallback).toHaveClass( 'bg-muted', 'flex', 'size-full', 'items-center', 'justify-center', 'rounded-full' ); }); test('custom classes are merged correctly', () => { render( T ); const avatar = screen.getByTestId('avatar-root'); const image = screen.getByTestId('avatar-image'); const fallback = screen.getByTestId('avatar-fallback'); expect(avatar).toHaveClass('w-12', 'h-12'); expect(image).toHaveClass('object-cover'); expect(fallback).toHaveClass('text-lg'); }); }); describe('Edge Cases', () => { test('handles empty children', () => { render(); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toBeInTheDocument(); expect(avatar.children).toHaveLength(0); }); test('handles multiple images (should not happen but test robustness)', () => { render( ); const images = screen.getAllByTestId('avatar-image'); expect(images).toHaveLength(2); }); test('handles multiple fallbacks (should not happen but test robustness)', () => { render( F1 F2 ); const fallbacks = screen.getAllByTestId('avatar-fallback'); expect(fallbacks).toHaveLength(2); expect(screen.getByText('F1')).toBeInTheDocument(); expect(screen.getByText('F2')).toBeInTheDocument(); }); test('handles undefined props gracefully', () => { render( Test ); expect(screen.getByTestId('avatar-root')).toBeInTheDocument(); expect(screen.getByTestId('avatar-image')).toBeInTheDocument(); expect(screen.getByTestId('avatar-fallback')).toBeInTheDocument(); expect(screen.getByText('Test')).toBeInTheDocument(); }); }); describe('Integration with User Data', () => { test('can be used with user profile data', () => { const userData = { name: 'John Doe', avatar: 'https://example.com/avatar.jpg', initials: 'JD', }; render( {userData.initials} ); const image = screen.getByTestId('avatar-image'); const fallback = screen.getByTestId('avatar-fallback'); expect(image).toHaveAttribute('src', userData.avatar); expect(image).toHaveAttribute('alt', userData.name); expect(fallback).toHaveTextContent(userData.initials); }); test('handles user data with missing avatar', () => { const userData = { name: 'Jane Smith', initials: 'JS', }; render( {userData.initials} ); expect(screen.queryByTestId('avatar-image')).not.toBeInTheDocument(); expect(screen.getByTestId('avatar-fallback')).toBeInTheDocument(); expect(screen.getByText(userData.initials)).toBeInTheDocument(); }); }); describe('Accessibility', () => { test('supports screen reader with proper labeling', () => { render( UP ); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toHaveAttribute('aria-label', 'User profile picture'); const image = screen.getByTestId('avatar-image'); expect(image).toHaveAttribute('alt', 'Profile picture'); }); test('supports role attributes', () => { render( Click me ); const avatar = screen.getByTestId('avatar-root'); expect(avatar).toHaveAttribute('role', 'button'); expect(avatar).toHaveAttribute('tabIndex', '0'); }); }); });