Files
zn-ai/tests/chat-message-list.test.tsx
duanshuwen df600272d6 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.
2026-04-23 20:27:54 +08:00

154 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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-xlsxgithub-url。位置/tmp/minimax-xlsx',
toolStatuses: [
{
id: 'tool-3',
toolCallId: 'skills.install:run-3',
name: 'skills.install',
status: 'completed',
summary: '已安装并启用 skill minimax-xlsxgithub-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-xlsxgithub-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();
});
});