// @vitest-environment jsdom /** * ToolCallCard 组件测试(v0.7.4 引入 jsdom 组件测试) * * 覆盖:五状态渲染(pending/executing/success/error/blocked)、 * 工具名/参数/耗时/错误信息的条件渲染。 */ import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import { ToolCallCard } from '../ToolCallCard'; function makeToolCall(overrides: Partial[0]['toolCall']> = {}) { return { id: 'tc_1', name: 'read_file', args: {}, status: 'success' as const, durationMs: 120, ...overrides, }; } describe('ToolCallCard — 状态渲染', () => { it.each([ ['pending', '等待中'], ['executing', '执行中'], ['success', '成功'], ['error', '失败'], ['blocked', '已阻止'], ] as const)('%s 状态显示对应文案', (status, label) => { const { container } = render(); // Chip 的 label 可能在 DOM 中拆分,用 textContent 匹配 expect(container.textContent).toContain(label); }); it('显示工具名', () => { render(); expect(screen.getByText('list_directory')).toBeInTheDocument(); }); it('显示耗时(formatDuration 格式化)', () => { render(); expect(screen.getByText('1.5s')).toBeInTheDocument(); }); it('无耗时字段时不渲染耗时', () => { const { container } = render( , ); expect(container.textContent).not.toMatch(/s$/); }); }); describe('ToolCallCard — 参数与错误', () => { it('有参数时渲染 JSON 格式参数', () => { const args = { file_path: 'a.ts', offset: 10 }; render(); expect(screen.getByText(/"file_path"/)).toBeInTheDocument(); expect(screen.getByText(/"a\.ts"/)).toBeInTheDocument(); }); it('无参数时不渲染参数区', () => { const { container } = render(); expect(container.querySelector('pre')).toBeNull(); }); it('error 状态且有错误信息时渲染错误文本', () => { render( , ); expect(screen.getByText('Permission denied')).toBeInTheDocument(); }); it('error 状态但无错误信息时不渲染错误区', () => { const { container } = render( , ); expect(container.textContent).not.toContain('undefined'); }); it('非 error 状态即使有 error 字段也不渲染', () => { const { container } = render( , ); expect(container.textContent).not.toContain('should not show'); }); });