import React from 'react'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { setLocale } from '../src/i18n'; import ChatMessageList from '../src/components/chat/ChatMessageList'; const mocks = vi.hoisted(() => ({ apiOpenSkillPath: vi.fn(), apiOpenSkillReadme: vi.fn(), writeText: vi.fn(), })); vi.mock('../src/lib/skills-api', () => ({ apiOpenSkillPath: mocks.apiOpenSkillPath, apiOpenSkillReadme: mocks.apiOpenSkillReadme, })); describe('ChatMessageList', () => { beforeEach(() => { setLocale('zh'); vi.clearAllMocks(); mocks.apiOpenSkillPath.mockResolvedValue(undefined); mocks.apiOpenSkillReadme.mockResolvedValue(undefined); mocks.writeText.mockResolvedValue(undefined); Object.defineProperty(window.navigator, 'clipboard', { value: { writeText: mocks.writeText, }, configurable: true, }); }); it('renders standalone streaming tool status cards when there is no streaming assistant text yet', () => { render( , ); expect(screen.getByText('正在执行工具...')).toBeTruthy(); expect(screen.getByText('安装 Skill')).toBeTruthy(); expect(screen.getByText('运行中')).toBeTruthy(); expect(screen.getByText('Installing minimax-xlsx')).toBeTruthy(); }); it('renders streaming tool status cards above a streaming assistant message', () => { render( , ); expect(screen.getByText('打开网页')).toBeTruthy(); expect(screen.getByText('已完成')).toBeTruthy(); expect(screen.getByText('1.2s')).toBeTruthy(); expect(screen.getByText('已为你打开 http://www.baidu.com/')).toBeTruthy(); expect(screen.getByText('已安装完成')).toBeTruthy(); }); it('renders persistent skill-install tool cards with follow-up actions', async () => { render( , ); expect(screen.getAllByText('已安装并启用 skill minimax-xlsx(github-url)。位置:/tmp/minimax-xlsx')).toHaveLength(1); expect(screen.getByText('Skill')).toBeTruthy(); expect(screen.getByText('/tmp/minimax-xlsx')).toBeTruthy(); expect(screen.getByText('后续动作')).toBeTruthy(); fireEvent.click(screen.getByText('打开目录')); await waitFor(() => { expect(mocks.apiOpenSkillPath).toHaveBeenCalledWith( 'minimax-xlsx', 'minimax-xlsx', '/tmp/minimax-xlsx', ); }); fireEvent.click(screen.getByText('复制路径')); await waitFor(() => { expect(mocks.writeText).toHaveBeenCalledWith('/tmp/minimax-xlsx'); }); expect(screen.getByText('路径已复制')).toBeTruthy(); }); });