import { fireEvent, render, screen } from '@testing-library/react' import { describe, expect, it } from 'vitest' import { CredentialIcon } from './credential-icon' describe('CredentialIcon', () => { describe('Rendering', () => { it('should render without crashing', () => { render() expect(screen.getByText('T')).toBeInTheDocument() }) it('should render first letter when no avatar provided', () => { render() expect(screen.getByText('A')).toBeInTheDocument() }) it('should render image when avatarUrl is provided', () => { render() const img = screen.getByRole('img') expect(img).toBeInTheDocument() expect(img).toHaveAttribute('src', 'https://example.com/avatar.png') }) }) describe('Props', () => { it('should apply default size of 20px', () => { const { container } = render() const wrapper = container.firstChild as HTMLElement expect(wrapper).toHaveStyle({ width: '20px', height: '20px' }) }) it('should apply custom size', () => { const { container } = render() const wrapper = container.firstChild as HTMLElement expect(wrapper).toHaveStyle({ width: '40px', height: '40px' }) }) it('should apply custom className', () => { const { container } = render() const wrapper = container.firstChild as HTMLElement expect(wrapper).toHaveClass('custom-class') }) it('should uppercase the first letter', () => { render() expect(screen.getByText('B')).toBeInTheDocument() }) it('should render fallback when avatarUrl is "default"', () => { render() expect(screen.getByText('T')).toBeInTheDocument() expect(screen.queryByRole('img')).not.toBeInTheDocument() }) }) describe('User Interactions', () => { it('should fallback to letter when image fails to load', () => { render() // Initially shows image const img = screen.getByRole('img') expect(img).toBeInTheDocument() // Trigger error event fireEvent.error(img) // Should now show letter fallback expect(screen.getByText('T')).toBeInTheDocument() expect(screen.queryByRole('img')).not.toBeInTheDocument() }) }) describe('Edge Cases', () => { it('should handle single character name', () => { render() expect(screen.getByText('A')).toBeInTheDocument() }) it('should handle name starting with number', () => { render() expect(screen.getByText('1')).toBeInTheDocument() }) it('should handle name starting with special character', () => { render() expect(screen.getByText('@')).toBeInTheDocument() }) it('should assign consistent background colors based on first letter', () => { // Same first letter should get same color const { container: container1 } = render() const { container: container2 } = render() const wrapper1 = container1.firstChild as HTMLElement const wrapper2 = container2.firstChild as HTMLElement // Both should have the same bg class since they start with 'A' const classes1 = wrapper1.className const classes2 = wrapper2.className const bgClass1 = classes1.match(/bg-components-icon-bg-\S+/)?.[0] const bgClass2 = classes2.match(/bg-components-icon-bg-\S+/)?.[0] expect(bgClass1).toBe(bgClass2) }) it('should apply different background colors for different letters', () => { // 'A' (65) % 4 = 1 → pink, 'B' (66) % 4 = 2 → indigo const { container: container1 } = render() const { container: container2 } = render() const wrapper1 = container1.firstChild as HTMLElement const wrapper2 = container2.firstChild as HTMLElement const bgClass1 = wrapper1.className.match(/bg-components-icon-bg-\S+/)?.[0] const bgClass2 = wrapper2.className.match(/bg-components-icon-bg-\S+/)?.[0] expect(bgClass1).toBeDefined() expect(bgClass2).toBeDefined() expect(bgClass1).not.toBe(bgClass2) }) it('should handle empty avatarUrl string', () => { render() expect(screen.getByText('T')).toBeInTheDocument() expect(screen.queryByRole('img')).not.toBeInTheDocument() }) it('should render image with correct dimensions', () => { render() const img = screen.getByRole('img') expect(img).toHaveAttribute('width', '32') expect(img).toHaveAttribute('height', '32') }) }) })