207 lines
5.8 KiB
TypeScript
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 轮');
|
|
});
|