import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' import { describe, expect, it, vi } from 'vitest' import { BlockEnum } from '@/app/components/workflow/types' import ToolCallItem from './tool-call' vi.mock('@/app/components/workflow/nodes/_base/components/editor/code-editor', () => ({ default: ({ title, value }: { title: React.ReactNode, value: string | object }) => (
{title}
{JSON.stringify(value)}
), })) vi.mock('@/app/components/workflow/block-icon', () => ({ default: ({ type }: { type: BlockEnum }) =>
, })) const mockToolCall = { status: 'success', error: null, tool_name: 'test_tool', tool_label: { en: 'Test Tool Label' }, tool_icon: 'icon', time_cost: 1.5, tool_input: { query: 'hello' }, tool_output: { result: 'world' }, } describe('ToolCallItem', () => { it('should render tool name correctly for LLM', () => { render() expect(screen.getByText('LLM')).toBeInTheDocument() expect(screen.getByTestId('block-icon')).toHaveAttribute('data-type', BlockEnum.LLM) }) it('should render tool name from label for non-LLM', () => { render() expect(screen.getByText('Test Tool Label')).toBeInTheDocument() expect(screen.getByTestId('block-icon')).toHaveAttribute('data-type', BlockEnum.Tool) }) it('should format time correctly', () => { render() expect(screen.getByText('1.500 s')).toBeInTheDocument() // Test ms format render() expect(screen.getByText('500.000 ms')).toBeInTheDocument() // Test minute format render() expect(screen.getByText('1 m 5.000 s')).toBeInTheDocument() }) it('should format token count correctly', () => { render() expect(screen.getByText('1.2K tokens')).toBeInTheDocument() render() expect(screen.getByText('800 tokens')).toBeInTheDocument() render() expect(screen.getByText('1.2M tokens')).toBeInTheDocument() }) it('should handle collapse/expand', () => { render() expect(screen.queryByTestId('code-editor')).not.toBeInTheDocument() fireEvent.click(screen.getByText(/Test Tool Label/i)) expect(screen.getAllByTestId('code-editor')).toHaveLength(2) }) it('should display error message when status is error', () => { const errorToolCall = { ...mockToolCall, status: 'error', error: 'Something went wrong', } render() fireEvent.click(screen.getByText(/Test Tool Label/i)) expect(screen.getByText('Something went wrong')).toBeInTheDocument() }) it('should display LLM specific fields when expanded', () => { render( , ) fireEvent.click(screen.getByText('LLM')) const titles = screen.getAllByTestId('code-editor-title') const titleTexts = titles.map(t => t.textContent) expect(titleTexts).toContain('INPUT') expect(titleTexts).toContain('OUTPUT') expect(titleTexts).toContain('OBSERVATION') expect(titleTexts).toContain('FINAL ANSWER') }) it('should display THOUGHT instead of FINAL ANSWER when isFinal is false', () => { render( , ) fireEvent.click(screen.getByText('LLM')) expect(screen.getByText('THOUGHT')).toBeInTheDocument() expect(screen.queryByText('FINAL ANSWER')).not.toBeInTheDocument() }) })