收口运行态阶段加载提示
RPG runtime 主阶段懒加载提示改用 PlatformSubpanel 新增阶段路由加载提示的公共子面板断言 同步 PlatformUiKit 文档和 Hermes 决策记录
This commit is contained in:
161
src/components/rpg-runtime-shell/RpgRuntimeStageRouter.test.tsx
Normal file
161
src/components/rpg-runtime-shell/RpgRuntimeStageRouter.test.tsx
Normal file
@@ -0,0 +1,161 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
AnimationState,
|
||||
type GameState,
|
||||
} from '../../types';
|
||||
import {
|
||||
RpgRuntimeStageRouter,
|
||||
type RpgRuntimeStageRouterProps,
|
||||
} from './RpgRuntimeStageRouter';
|
||||
|
||||
vi.mock('../platform-entry/PlatformEntryFlowShell', () => ({
|
||||
PlatformEntryFlowShell: () => <div>平台首页</div>,
|
||||
}));
|
||||
|
||||
vi.mock('../rpg-entry/RpgEntryCharacterSelectView', () => ({
|
||||
RpgEntryCharacterSelectView: () => <div>角色选择</div>,
|
||||
}));
|
||||
|
||||
vi.mock('../rpg-runtime-panels/RpgRuntimePanelRouter', () => ({
|
||||
RpgRuntimePanelRouter: () => <div>冒险面板</div>,
|
||||
}));
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
function createGameState(overrides: Partial<GameState> = {}): GameState {
|
||||
return {
|
||||
worldType: null,
|
||||
customWorldProfile: null,
|
||||
playerCharacter: null,
|
||||
runtimeStats: {
|
||||
playTimeMs: 0,
|
||||
lastPlayTickAt: null,
|
||||
hostileNpcsDefeated: 0,
|
||||
questsAccepted: 0,
|
||||
itemsUsed: 0,
|
||||
scenesTraveled: 0,
|
||||
},
|
||||
currentScene: 'test-scene',
|
||||
storyHistory: [],
|
||||
characterChats: {},
|
||||
animationState: AnimationState.IDLE,
|
||||
currentEncounter: null,
|
||||
npcInteractionActive: false,
|
||||
currentScenePreset: null,
|
||||
sceneHostileNpcs: [],
|
||||
playerX: 0,
|
||||
playerOffsetY: 0,
|
||||
playerFacing: 'right',
|
||||
playerActionMode: 'idle',
|
||||
scrollWorld: false,
|
||||
inBattle: false,
|
||||
playerHp: 100,
|
||||
playerMaxHp: 100,
|
||||
playerMana: 30,
|
||||
playerMaxMana: 30,
|
||||
playerSkillCooldowns: {},
|
||||
activeCombatEffects: [],
|
||||
playerCurrency: 0,
|
||||
playerInventory: [],
|
||||
playerEquipment: {
|
||||
weapon: null,
|
||||
armor: null,
|
||||
relic: null,
|
||||
},
|
||||
npcStates: {},
|
||||
quests: [],
|
||||
roster: [],
|
||||
companions: [],
|
||||
currentBattleNpcId: null,
|
||||
currentNpcBattleMode: null,
|
||||
currentNpcBattleOutcome: null,
|
||||
sparReturnEncounter: null,
|
||||
sparPlayerHpBefore: null,
|
||||
sparPlayerMaxHpBefore: null,
|
||||
sparStoryHistoryBefore: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function buildProps(
|
||||
overrides: Partial<RpgRuntimeStageRouterProps> = {},
|
||||
): RpgRuntimeStageRouterProps {
|
||||
const gameState = createGameState();
|
||||
|
||||
return {
|
||||
gameState,
|
||||
visibleGameState: gameState,
|
||||
visibleCurrentStory: null,
|
||||
isLoading: false,
|
||||
aiError: null,
|
||||
bottomTab: 'adventure',
|
||||
setBottomTab: noop,
|
||||
selectionStage: 'platform',
|
||||
setSelectionStage: noop,
|
||||
isCharacterSelectionStage: false,
|
||||
hasSavedGame: false,
|
||||
savedSnapshot: null,
|
||||
handleContinueGame: noop,
|
||||
handleStartNewGame: noop,
|
||||
handleCustomWorldSelect: noop,
|
||||
handleBackToWorldSelect: noop,
|
||||
handleCharacterSelect: noop,
|
||||
displayedOptions: [],
|
||||
hideStoryOptions: false,
|
||||
canRefreshOptions: false,
|
||||
handleRefreshOptions: noop,
|
||||
refreshNpcChatOptions: () => false,
|
||||
handleSceneTransitionChoice: noop,
|
||||
handleNpcChatInput: () => false,
|
||||
exitNpcChat: () => false,
|
||||
characterChatUi: {} as RpgRuntimeStageRouterProps['characterChatUi'],
|
||||
inventoryUi: {} as RpgRuntimeStageRouterProps['inventoryUi'],
|
||||
battleRewardUi: {} as RpgRuntimeStageRouterProps['battleRewardUi'],
|
||||
questUi: {} as RpgRuntimeStageRouterProps['questUi'],
|
||||
npcChatQuestOfferUi:
|
||||
{} as RpgRuntimeStageRouterProps['npcChatQuestOfferUi'],
|
||||
goalUi: {} as RpgRuntimeStageRouterProps['goalUi'],
|
||||
companionRenderStates: [],
|
||||
characterChatSummaries: {},
|
||||
openOverlayPanel: noop,
|
||||
openCampModal: noop,
|
||||
openPartyMemberDetails: noop,
|
||||
adventureStatistics: {
|
||||
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.5,
|
||||
onMusicVolumeChange: noop,
|
||||
resetForSaveAndExit: noop,
|
||||
handleSaveAndExit: noop,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test('renders the main content loading fallback with PlatformSubpanel chrome', async () => {
|
||||
render(<RpgRuntimeStageRouter {...buildProps()} />);
|
||||
|
||||
const loadingLabel = screen.getByText('正在加载平台首页...');
|
||||
const panel = loadingLabel.closest('.platform-subpanel');
|
||||
|
||||
expect(panel).not.toBeNull();
|
||||
expect(panel?.className).toContain('rounded-[1rem]');
|
||||
expect(panel?.className).toContain('px-5 py-4');
|
||||
expect(panel?.className).toContain('text-zinc-300');
|
||||
await screen.findByText('平台首页');
|
||||
});
|
||||
@@ -19,6 +19,7 @@ import type {
|
||||
StoryOption,
|
||||
} from '../../types';
|
||||
import { UI_CHROME } from '../../uiAssets';
|
||||
import { PlatformSubpanel } from '../common/PlatformSubpanel';
|
||||
import type { GameCanvasEntitySelection } from '../GameCanvas';
|
||||
import type { SelectionStage } from '../platform-entry/platformEntryTypes';
|
||||
import type { RpgAdventureStatistics } from './types';
|
||||
@@ -47,9 +48,14 @@ const RpgRuntimePanelRouter = lazy(async () => {
|
||||
function MainContentLoadingFallback({ label }: { label: string }) {
|
||||
return (
|
||||
<div className="flex h-full min-h-0 items-center justify-center">
|
||||
<div className="platform-subpanel rounded-2xl px-5 py-4 text-sm text-zinc-300">
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
radius="sm"
|
||||
padding="none"
|
||||
className="px-5 py-4 text-sm text-zinc-300"
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user