import { describe, it, expect } from 'vitest' import { render, screen, fireEvent } from '@testing-library/react' import { ToolInvocationCard } from '../../chat/tool-invocation-card' describe('ToolInvocationCard', () => { // ============================================================ // 基础渲染测试 // ============================================================ describe('基础渲染', () => { it('应正确渲染工具名称', () => { render() expect(screen.getByText('read_file')).toBeInTheDocument() }) it('应设置正确的 displayName', () => { expect(ToolInvocationCard.displayName).toBe('ToolInvocationCard') }) it('应渲染参数文本', () => { render( ) expect(screen.getByText('query: hello world')).toBeInTheDocument() }) it('无参数时不应渲染参数区域', () => { const { container } = render( ) // 只有工具名和状态文本 expect(container.textContent).toContain('list_dir') }) }) // ============================================================ // 状态图标测试 // ============================================================ describe('状态图标', () => { it('running 状态应显示时间图标', () => { const { container } = render( ) // 默认 timeIcon 使用 TimeLine 组件 expect(container.querySelector('svg')).toBeInTheDocument() }) it('success 状态应显示勾选图标', () => { const { container } = render( ) expect(container.querySelector('svg')).toBeInTheDocument() }) it('error 状态应显示关闭图标', () => { const { container } = render( ) expect(container.querySelector('svg')).toBeInTheDocument() }) it('应接受自定义图标', () => { render( ✓} /> ) expect(screen.getByTestId('custom-check')).toBeInTheDocument() }) }) // ============================================================ // 状态文本测试 // ============================================================ describe('状态文本', () => { it('running 状态应显示默认文本 "Running"', () => { render() expect(screen.getByText('Running')).toBeInTheDocument() }) it('success 状态应显示默认文本 "Ran"', () => { render() expect(screen.getByText('Ran')).toBeInTheDocument() }) it('error 状态应显示默认文本 "Failed"', () => { render() expect(screen.getByText('Failed')).toBeInTheDocument() }) it('应接受自定义 statusText', () => { render( ) expect(screen.getByText('执行完成')).toBeInTheDocument() }) it('statusText 为空字符串时不应显示状态文本', () => { render( ) expect(screen.queryByText('Ran')).not.toBeInTheDocument() }) it('应接受自定义状态文本 props', () => { render( ) expect(screen.getByText('执行中')).toBeInTheDocument() }) }) // ============================================================ // 响应展示测试 // ============================================================ describe('响应展示', () => { it('有响应时应可展开', () => { render( ) // 点击展开 fireEvent.click(screen.getByText('test')) expect(screen.getByText('Tool output result')).toBeInTheDocument() }) it('defaultExpanded=true 时应默认展开', () => { render( ) expect(screen.getByText('Already expanded')).toBeInTheDocument() }) it('无响应时不应显示展开箭头', () => { const { container } = render( ) // 没有箭头图标(ArrowRightLine 的 SVG) const arrows = container.querySelectorAll('[class*="rotate"]') expect(arrows).toHaveLength(0) }) it('running 状态时不应可展开', () => { render( ) // running 状态下点击不应展开 fireEvent.click(screen.getByText('test')) expect(screen.queryByText('Some response')).not.toBeInTheDocument() }) it('点击应切换展开/收起状态', () => { render( ) const trigger = screen.getByText('toggle-test') // 第一次点击展开 fireEvent.click(trigger) expect(screen.getByText('Toggle content')).toBeInTheDocument() // 第二次点击收起 fireEvent.click(trigger) expect(screen.queryByText('Toggle content')).not.toBeInTheDocument() }) }) // ============================================================ // 响应标签测试 // ============================================================ describe('响应标签', () => { it('展开时应显示默认标签 "Response"', () => { render( ) expect(screen.getByText('Response')).toBeInTheDocument() }) it('应接受自定义 responseLabel', () => { render( ) expect(screen.getByText('输出结果')).toBeInTheDocument() }) }) // ============================================================ // 错误状态样式测试 // ============================================================ describe('错误状态', () => { it('error 状态响应应应用错误样式', () => { render( ) const errorText = screen.getByText('Error message') expect(errorText).toHaveClass('text-error') }) it('success 状态响应不应有错误样式', () => { render( ) const successText = screen.getByText('Success message') expect(successText).not.toHaveClass('text-error') }) }) // ============================================================ // className 测试 // ============================================================ describe('className', () => { it('应合并自定义 className', () => { const { container } = render( ) expect(container.firstChild).toHaveClass('custom-card') }) }) // ============================================================ // 自定义图标 props 测试 // ============================================================ describe('自定义图标 props', () => { it('应接受自定义 timeIcon', () => { render( ⏱} /> ) expect(screen.getByTestId('time-icon')).toBeInTheDocument() }) it('应接受自定义 closeCircleIcon', () => { render( ✗} /> ) expect(screen.getByTestId('close-icon')).toBeInTheDocument() }) it('应接受自定义 arrowRightIcon', () => { render( →} /> ) expect(screen.getByTestId('arrow-icon')).toBeInTheDocument() }) }) // ============================================================ // 组合场景测试 // ============================================================ describe('组合场景', () => { it('应支持所有 props 组合', () => { render( ✓} arrowRightIcon={} /> ) expect(screen.getByText('full_test')).toBeInTheDocument() expect(screen.getByText('/path/to/file.ts')).toBeInTheDocument() expect(screen.getByText('已完成')).toBeInTheDocument() expect(screen.getByText('文件内容')).toBeInTheDocument() expect(screen.getByText('File content here...')).toBeInTheDocument() expect(screen.getByTestId('check')).toBeInTheDocument() expect(screen.getByTestId('arrow')).toBeInTheDocument() }) }) })