Files
Genarrative/src/components/CharacterChatModal.test.tsx
kdletters 94122583ac 收口前端平台组件能力
新增 PlatformAsyncStatePanel 统一 profile 异步状态骨架
扩展 PlatformSegmentedTabs 支持滚动 tab 并接入创作入口与发现页
统一 PixelCloseButton 复用 PlatformModalCloseButton 像素关闭能力
抽取平台入口泥点前置提示弹层并收紧阻断语义
补充组件收口文档与共享决策记录
2026-06-11 01:06:31 +08:00

138 lines
4.3 KiB
TypeScript

/* @vitest-environment jsdom */
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { expect, test, vi } from 'vitest';
import type { CharacterChatModalState } from '../hooks/rpg-runtime-story';
import type { Character } from '../types';
import { CharacterChatModal } from './CharacterChatModal';
function createCharacter(): Character {
return {
id: 'hero',
name: '沈行',
title: '试剑客',
description: '测试角色',
backstory: '测试背景',
avatar: '/hero.png',
portrait: '/hero.png',
assetFolder: 'hero',
assetVariant: 'default',
attributes: {
strength: 10,
agility: 10,
intelligence: 8,
spirit: 9,
},
personality: '冷静谨慎',
skills: [],
adventureOpenings: {},
} as Character;
}
function createModalState(
overrides: Partial<CharacterChatModalState> = {},
): CharacterChatModalState {
return {
target: {
character: createCharacter(),
npcId: 'npc-hero',
roleLabel: '队友',
hp: 80,
maxHp: 100,
mana: 24,
maxMana: 30,
},
draft: '',
messages: [],
suggestions: ['先问问线索'],
summary: '',
isSending: false,
isLoadingSuggestions: false,
error: '暂时无法生成回复。',
...overrides,
};
}
test('角色聊天错误提示复用暗色 PlatformStatusMessage chrome', () => {
render(
<CharacterChatModal
modal={createModalState()}
onClose={vi.fn()}
onDraftChange={vi.fn()}
onUseSuggestion={vi.fn()}
onRefreshSuggestions={vi.fn()}
onSendDraft={vi.fn()}
/>,
);
const errorMessage = screen.getByText('暂时无法生成回复。');
expect(errorMessage.className).toContain('platform-status-message');
expect(errorMessage.className).toContain('border-amber-300/15');
expect(errorMessage.className).toContain('bg-amber-500/10');
expect(errorMessage.className).toContain('text-amber-50/90');
});
test('角色聊天状态、空态和建议复用暗色 UI Kit chrome', () => {
render(
<CharacterChatModal
modal={createModalState()}
onClose={vi.fn()}
onDraftChange={vi.fn()}
onUseSuggestion={vi.fn()}
onRefreshSuggestions={vi.fn()}
onSendDraft={vi.fn()}
/>,
);
const hpStatus = screen.getByText('生命值 80 / 100');
const summaryFallback = screen.getByText('你们还没有形成新的私下聊天总结。');
const emptyHistory = screen.getByText(
'这里会保留你和该角色的私下聊天记录。输入框支持自由发挥,上方三条文本可以帮你快速起句。',
);
const refreshButton = screen.getByRole('button', { name: '换一组' });
const suggestionButton = screen.getByRole('button', { name: '先问问线索' });
const draftTextarea = screen.getByPlaceholderText('对沈行说点什么...');
expect(hpStatus.className).toContain('border-white/10');
expect(hpStatus.className).toContain('bg-black/25');
expect(summaryFallback.className).toContain('border-white/10');
expect(summaryFallback.className).toContain('bg-black/25');
expect(emptyHistory.className).toContain('platform-empty-state');
expect(emptyHistory.className).toContain('border-dashed');
expect(refreshButton.className).toContain(
'platform-action-button--editor-dark',
);
expect(refreshButton.className).toContain('text-[10px]');
expect(suggestionButton.className).toContain('platform-dark-option-card');
expect(suggestionButton.className).toContain('border-white/8');
expect(draftTextarea.className).toContain('platform-text-field--editor-dark');
expect(draftTextarea.className).toContain('focus:border-sky-300/35');
});
test('角色聊天标题栏内联关闭按钮保持共享关闭行为', async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(
<CharacterChatModal
modal={createModalState()}
onClose={onClose}
onDraftChange={vi.fn()}
onUseSuggestion={vi.fn()}
onRefreshSuggestions={vi.fn()}
onSendDraft={vi.fn()}
/>,
);
const closeButton = screen.getByRole('button', { name: '关闭角色聊天' });
await user.click(closeButton);
expect(closeButton.className).toContain('relative');
expect(closeButton.className).toContain('shrink-0');
expect(closeButton.getAttribute('title')).toBe('关闭角色聊天');
expect(onClose).toHaveBeenCalledTimes(1);
});