This commit is contained in:
2026-04-28 02:05:12 +08:00
parent 271db02e4a
commit 1eb090e4a5
39 changed files with 2671 additions and 165 deletions

View File

@@ -83,7 +83,10 @@ vi.mock('./RpgRuntimeStageRouter', () => ({
let mockVisibleGameState: GameState;
function createGameState(runtimeMode: GameState['runtimeMode']): GameState {
function createGameState(
runtimeMode: GameState['runtimeMode'],
runtimePersistenceDisabled?: boolean,
): GameState {
return {
worldType: WorldType.CUSTOM,
customWorldProfile: null,
@@ -112,7 +115,7 @@ function createGameState(runtimeMode: GameState['runtimeMode']): GameState {
initialItems: [],
},
runtimeMode,
runtimePersistenceDisabled: runtimeMode !== 'play',
runtimePersistenceDisabled: runtimePersistenceDisabled ?? false,
runtimeStats: {
playTimeMs: 0,
lastPlayTickAt: null,
@@ -168,8 +171,11 @@ function createGameState(runtimeMode: GameState['runtimeMode']): GameState {
};
}
function buildProps(runtimeMode: GameState['runtimeMode']): RpgRuntimeShellProps {
const gameState = createGameState(runtimeMode);
function buildProps(
runtimeMode: GameState['runtimeMode'],
runtimePersistenceDisabled?: boolean,
): RpgRuntimeShellProps {
const gameState = createGameState(runtimeMode, runtimePersistenceDisabled);
mockVisibleGameState = gameState;
return {
session: {
@@ -254,24 +260,25 @@ beforeEach(() => {
mockVisibleGameState = createGameState('play');
});
test('测试态显示结束测试按钮并触发退出回调', async () => {
test('结果页测试入口可显示结束测试按钮并触发退出回调', async () => {
const user = userEvent.setup();
const onExitTestRuntime = vi.fn();
const onExitRuntimePreview = vi.fn();
render(
<RpgRuntimeShell
{...buildProps('test')}
onExitTestRuntime={onExitTestRuntime}
{...buildProps('play', true)}
onExitRuntimePreview={onExitRuntimePreview}
showRuntimePreviewExit
/>,
);
await user.click(screen.getByRole('button', { name: '结束测试' }));
expect(onExitTestRuntime).toHaveBeenCalledTimes(1);
expect(onExitRuntimePreview).toHaveBeenCalledTimes(1);
});
test('正式运行态不显示结束测试按钮', () => {
render(<RpgRuntimeShell {...buildProps('play')} onExitTestRuntime={() => {}} />);
render(<RpgRuntimeShell {...buildProps('play')} />);
expect(screen.queryByRole('button', { name: '结束测试' })).toBeNull();
});

View File

@@ -37,7 +37,8 @@ export function RpgRuntimeShell({
companions,
audio,
chrome,
onExitTestRuntime,
onExitRuntimePreview,
showRuntimePreviewExit,
}: RpgRuntimeShellComponentProps) {
const authUi = useAuthUi();
const isPlatformShell = !session.gameState.worldType;
@@ -133,7 +134,10 @@ export function RpgRuntimeShell({
playerProgression.currentLevelXp / playerProgression.xpToNextLevel,
),
);
const isTestRuntime = gameState.runtimeMode === 'test';
const canExitRuntimePreview =
Boolean(gameState.worldType) &&
Boolean(showRuntimePreviewExit) &&
Boolean(onExitRuntimePreview);
useEffect(() => {
if (gameState.worldType && !gameState.playerCharacter) {
@@ -209,7 +213,7 @@ export function RpgRuntimeShell({
</div>
)}
{gameState.worldType && isTestRuntime && onExitTestRuntime ? (
{canExitRuntimePreview ? (
<div
className="fixed inset-x-0 z-[170] flex justify-center px-4"
style={{
@@ -218,7 +222,7 @@ export function RpgRuntimeShell({
>
<button
type="button"
onClick={onExitTestRuntime}
onClick={onExitRuntimePreview}
className="inline-flex min-h-[2.75rem] items-center justify-center rounded-full border border-white/15 bg-black/65 px-5 text-sm font-semibold text-white shadow-[0_12px_30px_rgba(0,0,0,0.38)] backdrop-blur-sm transition hover:border-white/28 hover:bg-black/78"
>

View File

@@ -111,5 +111,6 @@ export interface RpgRuntimeShellProps {
companions: RpgRuntimeCompanionProps;
audio: RpgRuntimeAudioProps;
chrome?: RpgRuntimeShellChromeOptions;
onExitTestRuntime?: () => void;
onExitRuntimePreview?: () => void;
showRuntimePreviewExit?: boolean;
}