dify/web/app/components/base/avatar/__tests__/index.spec.tsx

112 lines
3.9 KiB
TypeScript

import { render, screen } from '@testing-library/react'
import { Avatar } from '../index'
describe('Avatar', () => {
describe('Rendering', () => {
it('should keep the fallback visible when avatar URL is provided before image load', () => {
render(<Avatar name="John Doe" avatar="https://example.com/avatar.jpg" />)
expect(screen.getByText('J')).toBeInTheDocument()
})
it('should render fallback with uppercase initial when avatar is null', () => {
render(<Avatar name="alice" avatar={null} />)
expect(screen.queryByRole('img')).not.toBeInTheDocument()
expect(screen.getByText('A')).toBeInTheDocument()
})
it('should render the fallback when avatar is provided', () => {
render(<Avatar name="John" avatar="https://example.com/avatar.jpg" />)
expect(screen.getByText('J')).toBeInTheDocument()
})
})
describe('Size variants', () => {
it.each([
{ size: 'xxs' as const, expectedClass: 'size-4' },
{ size: 'xs' as const, expectedClass: 'size-5' },
{ size: 'sm' as const, expectedClass: 'size-6' },
{ size: 'md' as const, expectedClass: 'size-8' },
{ size: 'lg' as const, expectedClass: 'size-9' },
{ size: 'xl' as const, expectedClass: 'size-10' },
{ size: '2xl' as const, expectedClass: 'size-12' },
{ size: '3xl' as const, expectedClass: 'size-16' },
])('should apply $expectedClass for size="$size"', ({ size, expectedClass }) => {
const { container } = render(<Avatar name="Test" avatar={null} size={size} />)
const root = container.firstElementChild as HTMLElement
expect(root).toHaveClass(expectedClass)
})
it('should default to md size when size is not specified', () => {
const { container } = render(<Avatar name="Test" avatar={null} />)
const root = container.firstElementChild as HTMLElement
expect(root).toHaveClass('size-8')
})
})
describe('className prop', () => {
it('should merge className with avatar variant classes on root', () => {
const { container } = render(
<Avatar name="Test" avatar={null} className="custom-class" />,
)
const root = container.firstElementChild as HTMLElement
expect(root).toHaveClass('custom-class')
expect(root).toHaveClass('rounded-full', 'bg-primary-600')
})
})
describe('Edge Cases', () => {
it('should handle empty string name gracefully', () => {
const { container } = render(<Avatar name="" avatar={null} />)
const fallback = container.querySelector('.text-white') as HTMLElement
expect(fallback).toBeInTheDocument()
expect(fallback.textContent).toBe('')
})
it.each([
{ name: '中文名', expected: '中', label: 'Chinese characters' },
{ name: '123User', expected: '1', label: 'number' },
])('should display first character when name starts with $label', ({ name, expected }) => {
render(<Avatar name={name} avatar={null} />)
expect(screen.getByText(expected)).toBeInTheDocument()
})
it('should handle empty string avatar as falsy value', () => {
render(<Avatar name="Test" avatar={'' as string | null} />)
expect(screen.queryByRole('img')).not.toBeInTheDocument()
expect(screen.getByText('T')).toBeInTheDocument()
})
})
describe('onLoadingStatusChange', () => {
it('should render the fallback when avatar and onLoadingStatusChange are provided', () => {
render(
<Avatar
name="John"
avatar="https://example.com/avatar.jpg"
onLoadingStatusChange={vi.fn()}
/>,
)
expect(screen.getByText('J')).toBeInTheDocument()
})
it('should not render image when avatar is null even with onLoadingStatusChange', () => {
const onStatusChange = vi.fn()
render(
<Avatar name="John" avatar={null} onLoadingStatusChange={onStatusChange} />,
)
expect(screen.queryByRole('img')).not.toBeInTheDocument()
})
})
})