import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { ThinkingIndicator } from '../../chat/thinking-indicator'
describe('ThinkingIndicator', () => {
// ============================================================
// 渲染测试
// ============================================================
describe('渲染', () => {
it('应正确渲染组件', () => {
const { container } = render()
expect(container.firstChild).toBeInTheDocument()
})
it('应设置正确的 displayName', () => {
expect(ThinkingIndicator.displayName).toBe('ThinkingIndicator')
})
})
// ============================================================
// 文案测试
// ============================================================
describe('text 文案', () => {
it('应显示默认文案 "Spark is Thinking..."', () => {
render()
expect(screen.getByText('Spark is Thinking...')).toBeInTheDocument()
})
it('应显示自定义文案', () => {
render()
expect(screen.getByText('正在思考...')).toBeInTheDocument()
})
it('空文案应正常渲染', () => {
const { container } = render()
expect(container.firstChild).toBeInTheDocument()
})
it('长文案应正常渲染', () => {
const longText = 'AI is analyzing your complex multi-step request with deep reasoning...'
render()
expect(screen.getByText(longText)).toBeInTheDocument()
})
})
// ============================================================
// Loader Slot 测试
// ============================================================
describe('loader slot', () => {
it('无 loader prop 时应渲染默认三点动画', () => {
const { container } = render()
expect(container.querySelector('.thinking-dots')).toBeInTheDocument()
})
it('默认动画应包含三个点', () => {
const { container } = render()
const dots = container.querySelectorAll('.thinking-dots span')
expect(dots).toHaveLength(3)
})
it('有 loader prop 时应渲染自定义 loader', () => {
render(
Custom Loader}
/>
)
expect(screen.getByTestId('custom-loader')).toBeInTheDocument()
})
it('自定义 loader 时不应渲染默认动画', () => {
const { container } = render(
Custom}
/>
)
expect(container.querySelector('.thinking-dots')).not.toBeInTheDocument()
})
it('loader 可以是复杂 React 节点', () => {
render(
Loading
...
}
/>
)
expect(screen.getByTestId('complex-loader')).toBeInTheDocument()
})
})
// ============================================================
// Shimmer 效果测试
// ============================================================
describe('shimmer 效果', () => {
it('默认应启用 shimmer 效果', () => {
render()
// shimmer 使用 motion.span,在测试环境被 mock 为普通 span
expect(screen.getByText('Test')).toBeInTheDocument()
})
it('shimmer=true 时文本应有渐变样式类', () => {
render()
const textElement = screen.getByText('Shimmer Text')
expect(textElement).toHaveClass('bg-clip-text')
expect(textElement).toHaveClass('text-transparent')
})
it('shimmer=false 时应显示静态文本', () => {
render()
const textElement = screen.getByText('Static Text')
expect(textElement).toHaveClass('text-text-secondary')
expect(textElement).not.toHaveClass('text-transparent')
})
})
// ============================================================
// Shimmer 配置测试
// ============================================================
describe('shimmer 配置', () => {
it('应接受自定义 shimmerDuration', () => {
// shimmerDuration 用于动画,测试环境动画被 mock,仅验证 prop 接受
const { container } = render(
)
expect(container.firstChild).toBeInTheDocument()
})
it('应接受自定义 shimmerSpread', () => {
const { container } = render(
)
expect(container.firstChild).toBeInTheDocument()
})
})
// ============================================================
// textClassName 测试
// ============================================================
describe('textClassName', () => {
it('应将 textClassName 应用到文本元素', () => {
render(
)
const textElement = screen.getByText('Styled Text')
expect(textElement).toHaveClass('custom-text-class')
})
it('textClassName 应与默认类名共存', () => {
render(
)
const textElement = screen.getByText('Mixed Classes')
expect(textElement).toHaveClass('my-class')
expect(textElement).toHaveClass('text-sm')
})
})
// ============================================================
// className 覆盖测试
// ============================================================
describe('className', () => {
it('应合并自定义 className 到根元素', () => {
const { container } = render(
)
expect(container.firstChild).toHaveClass('custom-root-class')
})
it('自定义 className 应与默认布局类共存', () => {
const { container } = render(
)
expect(container.firstChild).toHaveClass('my-indicator')
expect(container.firstChild).toHaveClass('inline-flex')
expect(container.firstChild).toHaveClass('items-center')
})
})
// ============================================================
// 原生属性透传测试
// ============================================================
describe('原生属性透传', () => {
it('应透传 data-* 属性', () => {
render()
expect(screen.getByTestId('thinking')).toBeInTheDocument()
})
it('应透传 id 属性', () => {
const { container } = render()
expect(container.querySelector('#my-indicator')).toBeInTheDocument()
})
it('应透传 aria-* 属性', () => {
const { container } = render(
)
expect(container.firstChild).toHaveAttribute('aria-label', 'AI is thinking')
})
})
// ============================================================
// 组合场景测试
// ============================================================
describe('组合场景', () => {
it('应支持所有 props 组合', () => {
render(
⟳}
/>
)
const root = screen.getByTestId('full-config')
expect(root).toHaveClass('root-class')
expect(screen.getByText('完整配置测试')).toHaveClass('text-class')
expect(screen.getByTestId('custom-spinner')).toBeInTheDocument()
})
it('shimmer=false 时 loader 仍可自定义', () => {
render(
●}
/>
)
expect(screen.getByTestId('static-loader')).toBeInTheDocument()
expect(screen.getByText('No Shimmer')).toHaveClass('text-text-secondary')
})
})
})