Files
Genarrative/src/components/rpg-runtime-panels/RpgAdventurePanel.npcChat.test.tsx
2026-04-21 18:27:46 +08:00

207 lines
5.8 KiB
TypeScript

import { renderToStaticMarkup } from 'react-dom/server';
import { expect, test } from 'vitest';
import { type Character, type StoryMoment, WorldType } from '../../types';
import { RpgAdventurePanel } from './RpgAdventurePanel';
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: 'calm',
skills: [],
adventureOpenings: {},
} as Character;
}
test('adventure panel renders system turns without special relationship labels', () => {
const currentStory: StoryMoment = {
text: '你们的语气忽然冷了下来。',
displayMode: 'dialogue',
dialogue: [
{ speaker: 'npc', speakerName: '柳无声', text: '这件事你最好别再追问。' },
{ speaker: 'system', text: '这轮交谈先在这里收束。' },
],
options: [],
};
const html = renderToStaticMarkup(
<RpgAdventurePanel
aiError={null}
currentStory={currentStory}
isLoading={false}
displayedOptions={[]}
hideOptions={false}
canRefreshOptions={false}
onRefreshOptions={() => undefined}
onChoice={() => undefined}
onOpenCharacter={() => undefined}
onOpenInventory={() => undefined}
playerCharacter={createCharacter()}
worldType={WorldType.WUXIA}
quests={[]}
questUi={{
acknowledgeQuestCompletion: () => undefined,
claimQuestReward: () => null,
}}
npcChatQuestOfferUi={{
replacePendingOffer: () => false,
abandonPendingOffer: () => false,
acceptPendingOffer: () => null,
}}
goalStack={{
northStarGoal: null,
activeGoal: null,
immediateStepGoal: null,
supportGoals: [],
}}
goalPulse={null}
onDismissGoalPulse={() => undefined}
battleRewardUi={{
reward: null,
dismiss: () => undefined,
}}
playerHp={100}
playerMaxHp={100}
playerMana={20}
playerMaxMana={20}
playerSkillCooldowns={{}}
inBattle={false}
currentNpcBattleMode={null}
statistics={{
playTimeMs: 0,
hostileNpcsDefeated: 0,
questsAccepted: 0,
questsCompleted: 0,
questsTurnedIn: 0,
itemsUsed: 0,
scenesTraveled: 0,
currentSceneName: '竹林古道',
playerCurrency: 0,
inventoryItemCount: 0,
inventoryStackCount: 0,
activeCompanionCount: 0,
rosterCompanionCount: 0,
}}
musicVolume={0.6}
onMusicVolumeChange={() => undefined}
onSaveAndExit={() => undefined}
/>,
);
expect(html).toContain('系统');
expect(html).toContain('这轮交谈先在这里收束。');
expect(html).not.toContain('关系变化');
});
test('adventure panel shows current act label and remaining turns for limited hostile npc chat', () => {
const currentStory: StoryMoment = {
text: '断桥客仍在压着最后那半句真相。',
displayMode: 'dialogue',
dialogue: [
{ speaker: 'player', text: '你到底还在替谁守着这座桥?' },
{ speaker: 'npc', speakerName: '断桥客', text: '你还没资格知道全名。' },
],
options: [],
npcChatState: {
npcId: 'npc-rival',
npcName: '断桥客',
turnCount: 3,
customInputPlaceholder: '输入你想对 TA 说的话',
sceneActId: 'scene-bridge-act-1',
turnLimit: 5,
remainingTurns: 2,
limitReason: 'negative_affinity',
forceExitAfterTurn: false,
},
};
const html = renderToStaticMarkup(
<RpgAdventurePanel
aiError={null}
currentStory={currentStory}
isLoading={false}
displayedOptions={[]}
hideOptions={false}
canRefreshOptions={false}
onRefreshOptions={() => undefined}
onChoice={() => undefined}
onSubmitNpcChatInput={() => true}
onExitNpcChat={() => true}
onOpenCharacter={() => undefined}
onOpenInventory={() => undefined}
playerCharacter={createCharacter()}
worldType={WorldType.WUXIA}
quests={[]}
questUi={{
acknowledgeQuestCompletion: () => undefined,
claimQuestReward: () => null,
}}
npcChatQuestOfferUi={{
replacePendingOffer: () => false,
abandonPendingOffer: () => false,
acceptPendingOffer: () => null,
}}
goalStack={{
northStarGoal: null,
activeGoal: null,
immediateStepGoal: null,
supportGoals: [],
}}
goalPulse={null}
onDismissGoalPulse={() => undefined}
battleRewardUi={{
reward: null,
dismiss: () => undefined,
}}
playerHp={100}
playerMaxHp={100}
playerMana={20}
playerMaxMana={20}
playerSkillCooldowns={{}}
inBattle={false}
currentNpcBattleMode={null}
statistics={{
playTimeMs: 0,
hostileNpcsDefeated: 0,
questsAccepted: 0,
questsCompleted: 0,
questsTurnedIn: 0,
itemsUsed: 0,
scenesTraveled: 0,
currentSceneName: '断桥口',
playerCurrency: 0,
inventoryItemCount: 0,
inventoryStackCount: 0,
activeCompanionCount: 0,
rosterCompanionCount: 0,
}}
musicVolume={0.6}
onMusicVolumeChange={() => undefined}
onSaveAndExit={() => undefined}
currentSceneActTitle="断桥口 · 对峙幕"
currentSceneActIndex={1}
currentSceneActCount={3}
/>,
);
expect(html).toContain('当前幕');
expect(html).toContain('断桥口 · 对峙幕');
expect(html).toContain('1/3');
expect(html).toContain('剩余交谈');
expect(html).toContain('2 轮');
});