/* @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 { 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( , ); 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( , ); 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( , ); 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); });