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();
});
});