1
This commit is contained in:
126
src/components/puzzle-runtime/PuzzleRuntimeShell.test.tsx
Normal file
126
src/components/puzzle-runtime/PuzzleRuntimeShell.test.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { fireEvent, render, screen, within } from '@testing-library/react';
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import type { PuzzleRunSnapshot } from '../../../packages/shared/src/contracts/puzzleRuntimeSession';
|
||||
import { PuzzleRuntimeShell } from './PuzzleRuntimeShell';
|
||||
|
||||
vi.mock('../../hooks/useResolvedAssetReadUrl', () => ({
|
||||
useResolvedAssetReadUrl: () => ({
|
||||
resolvedUrl: '',
|
||||
isResolving: false,
|
||||
shouldResolve: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('../ResolvedAssetImage', () => ({
|
||||
ResolvedAssetImage: () => null,
|
||||
}));
|
||||
|
||||
const clearedRun: PuzzleRunSnapshot = {
|
||||
runId: 'run-1',
|
||||
entryProfileId: 'profile-1',
|
||||
clearedLevelCount: 1,
|
||||
currentLevelIndex: 1,
|
||||
currentGridSize: 3,
|
||||
playedProfileIds: ['profile-1'],
|
||||
previousLevelTags: ['奇幻'],
|
||||
recommendedNextProfileId: 'profile-2',
|
||||
leaderboardEntries: [
|
||||
{
|
||||
rank: 1,
|
||||
nickname: '测试作者',
|
||||
elapsedMs: 12_340,
|
||||
isCurrentPlayer: true,
|
||||
},
|
||||
{
|
||||
rank: 2,
|
||||
nickname: '星桥旅人',
|
||||
elapsedMs: 18_120,
|
||||
},
|
||||
],
|
||||
currentLevel: {
|
||||
runId: 'run-1',
|
||||
levelIndex: 1,
|
||||
gridSize: 3,
|
||||
profileId: 'profile-1',
|
||||
levelName: '潮雾拼图',
|
||||
authorDisplayName: '测试作者',
|
||||
themeTags: ['奇幻'],
|
||||
coverImageSrc: null,
|
||||
status: 'cleared',
|
||||
startedAtMs: 1000,
|
||||
clearedAtMs: 13_340,
|
||||
elapsedMs: 12_340,
|
||||
leaderboardEntries: [
|
||||
{
|
||||
rank: 1,
|
||||
nickname: '测试作者',
|
||||
elapsedMs: 12_340,
|
||||
isCurrentPlayer: true,
|
||||
},
|
||||
{
|
||||
rank: 2,
|
||||
nickname: '星桥旅人',
|
||||
elapsedMs: 18_120,
|
||||
},
|
||||
],
|
||||
board: {
|
||||
rows: 3,
|
||||
cols: 3,
|
||||
selectedPieceId: null,
|
||||
allTilesResolved: true,
|
||||
mergedGroups: [],
|
||||
pieces: Array.from({ length: 9 }, (_, index) => ({
|
||||
pieceId: `piece-${index}`,
|
||||
correctRow: Math.floor(index / 3),
|
||||
correctCol: index % 3,
|
||||
currentRow: Math.floor(index / 3),
|
||||
currentCol: index % 3,
|
||||
mergedGroupId: null,
|
||||
})),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test('通关后显示结算弹窗、排行榜和下一关按钮', () => {
|
||||
const onAdvanceNextLevel = vi.fn();
|
||||
|
||||
render(
|
||||
<PuzzleRuntimeShell
|
||||
run={clearedRun}
|
||||
onBack={vi.fn()}
|
||||
onSwapPieces={vi.fn()}
|
||||
onDragPiece={vi.fn()}
|
||||
onAdvanceNextLevel={onAdvanceNextLevel}
|
||||
/>,
|
||||
);
|
||||
|
||||
const dialog = screen.getByRole('dialog', { name: '通关完成' });
|
||||
expect(within(dialog).getAllByText('0:12.34').length).toBeGreaterThan(0);
|
||||
expect(within(dialog).getByText('排行榜')).toBeTruthy();
|
||||
expect(within(dialog).getByText('#1')).toBeTruthy();
|
||||
expect(within(dialog).getByText('测试作者')).toBeTruthy();
|
||||
|
||||
fireEvent.click(within(dialog).getByRole('button', { name: '下一关' }));
|
||||
|
||||
expect(onAdvanceNextLevel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('关闭通关弹窗后保留底部下一关入口', () => {
|
||||
render(
|
||||
<PuzzleRuntimeShell
|
||||
run={clearedRun}
|
||||
onBack={vi.fn()}
|
||||
onSwapPieces={vi.fn()}
|
||||
onDragPiece={vi.fn()}
|
||||
onAdvanceNextLevel={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '关闭通关弹窗' }));
|
||||
|
||||
expect(screen.queryByRole('dialog', { name: '通关完成' })).toBeNull();
|
||||
expect(screen.getByRole('button', { name: /下一关/u })).toBeTruthy();
|
||||
});
|
||||
Reference in New Issue
Block a user