feat: add tool status management and localization for skill installation
- Updated chat message types to include tool statuses. - Enhanced localization files for English, Thai, and Chinese to support new tool status messages. - Modified HomePage and SkillsPage components to handle tool statuses in chat messages. - Implemented tool status merging and updating logic in the chat store. - Added handling for tool status events in the gateway event processing. - Created tests for chat message rendering with tool statuses and skill installation shortcuts. - Improved gateway event dispatching for tool lifecycle events.
This commit is contained in:
153
tests/chat-message-list.test.tsx
Normal file
153
tests/chat-message-list.test.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
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(
|
||||
<ChatMessageList
|
||||
messages={[
|
||||
{
|
||||
id: 'user-1',
|
||||
role: 'user',
|
||||
name: '你',
|
||||
time: '10:00',
|
||||
content: '帮我安装这个 skill',
|
||||
},
|
||||
]}
|
||||
streamingTools={[
|
||||
{
|
||||
id: 'tool-1',
|
||||
toolCallId: 'skills.install:run-1',
|
||||
name: 'skills.install',
|
||||
status: 'running',
|
||||
summary: 'Installing minimax-xlsx',
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
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(
|
||||
<ChatMessageList
|
||||
messages={[
|
||||
{
|
||||
id: 'assistant-stream',
|
||||
role: 'assistant',
|
||||
name: 'YINIAN',
|
||||
time: '10:01',
|
||||
content: '已安装完成',
|
||||
isStreaming: true,
|
||||
},
|
||||
]}
|
||||
streamingTools={[
|
||||
{
|
||||
id: 'tool-2',
|
||||
toolCallId: 'browser.open_url:run-2',
|
||||
name: 'browser.open_url',
|
||||
status: 'completed',
|
||||
durationMs: 1200,
|
||||
summary: '已为你打开 http://www.baidu.com/',
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
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(
|
||||
<ChatMessageList
|
||||
messages={[
|
||||
{
|
||||
id: 'assistant-1',
|
||||
role: 'assistant',
|
||||
name: 'YINIAN',
|
||||
time: '10:03',
|
||||
content: '已安装并启用 skill minimax-xlsx(github-url)。位置:/tmp/minimax-xlsx',
|
||||
toolStatuses: [
|
||||
{
|
||||
id: 'tool-3',
|
||||
toolCallId: 'skills.install:run-3',
|
||||
name: 'skills.install',
|
||||
status: 'completed',
|
||||
summary: '已安装并启用 skill minimax-xlsx(github-url)。位置:/tmp/minimax-xlsx',
|
||||
durationMs: 980,
|
||||
updatedAt: Date.now(),
|
||||
input: {
|
||||
kind: 'github-url',
|
||||
url: 'https://github.com/MiniMax-AI/skills/blob/main/skills/minimax-xlsx/SKILL.md',
|
||||
},
|
||||
result: {
|
||||
slug: 'minimax-xlsx',
|
||||
source: 'github-url',
|
||||
baseDir: '/tmp/minimax-xlsx',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user