1
This commit is contained in:
@@ -688,6 +688,76 @@ test('道具使用失败时保留确认弹窗和暂停态', async () => {
|
||||
expect(onPauseChange).toHaveBeenLastCalledWith(true);
|
||||
});
|
||||
|
||||
test('冻结确认期间后端同步失败态时关闭确认窗并展示失败面板', async () => {
|
||||
const onUseProp = vi.fn().mockResolvedValue({
|
||||
...clearedRun,
|
||||
currentLevel: {
|
||||
...clearedRun.currentLevel!,
|
||||
status: 'failed',
|
||||
elapsedMs: 180_000,
|
||||
remainingMs: 0,
|
||||
board: {
|
||||
...clearedRun.currentLevel!.board,
|
||||
allTilesResolved: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
const playingRun: PuzzleRunSnapshot = {
|
||||
...clearedRun,
|
||||
currentLevel: {
|
||||
...clearedRun.currentLevel!,
|
||||
status: 'playing',
|
||||
startedAtMs: Date.now(),
|
||||
remainingMs: 180_000,
|
||||
board: {
|
||||
...clearedRun.currentLevel!.board,
|
||||
allTilesResolved: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { rerender } = renderPuzzleRuntime(
|
||||
<PuzzleRuntimeShell
|
||||
run={playingRun}
|
||||
onBack={vi.fn()}
|
||||
onSwapPieces={vi.fn()}
|
||||
onDragPiece={vi.fn()}
|
||||
onAdvanceNextLevel={vi.fn()}
|
||||
onUseProp={onUseProp}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '冻结' }));
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '确定' }));
|
||||
});
|
||||
|
||||
rerender(
|
||||
<AuthUiContext.Provider value={createAuthValue()}>
|
||||
<PuzzleRuntimeShell
|
||||
run={{
|
||||
...playingRun,
|
||||
currentLevel: {
|
||||
...playingRun.currentLevel!,
|
||||
status: 'failed',
|
||||
elapsedMs: 180_000,
|
||||
remainingMs: 0,
|
||||
},
|
||||
}}
|
||||
onBack={vi.fn()}
|
||||
onSwapPieces={vi.fn()}
|
||||
onDragPiece={vi.fn()}
|
||||
onAdvanceNextLevel={vi.fn()}
|
||||
onUseProp={onUseProp}
|
||||
/>
|
||||
</AuthUiContext.Provider>,
|
||||
);
|
||||
|
||||
expect(screen.queryByRole('dialog', { name: '冻结时间' })).toBeNull();
|
||||
expect(screen.getByRole('dialog', { name: '关卡失败' })).toBeTruthy();
|
||||
expect(screen.queryByTestId('puzzle-freeze-effect')).toBeNull();
|
||||
});
|
||||
|
||||
test('倒计时归零时通知父层同步失败态', () => {
|
||||
vi.useFakeTimers();
|
||||
const onTimeExpired = vi.fn();
|
||||
|
||||
@@ -430,6 +430,7 @@ export function PuzzleRuntimeShell({
|
||||
const mergeFlashTimeoutRef = useRef<number | null>(null);
|
||||
const boardRef = useRef<HTMLDivElement | null>(null);
|
||||
const currentLevel = run?.currentLevel ?? null;
|
||||
const currentLevelRef = useRef(currentLevel);
|
||||
const board = currentLevel?.board ?? null;
|
||||
const displayRemainingMs = currentLevel
|
||||
? resolveRuntimeRemainingMs(currentLevel, timerNowMs, uiPauseStartedAtMs)
|
||||
@@ -448,6 +449,10 @@ export function PuzzleRuntimeShell({
|
||||
currentLevel?.coverImageSrc ?? null,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
currentLevelRef.current = currentLevel;
|
||||
}, [currentLevel]);
|
||||
|
||||
const pieces = useMemo<PuzzleBoardPieceViewModel[]>(() => {
|
||||
if (!board) {
|
||||
return [];
|
||||
@@ -1068,9 +1073,10 @@ export function PuzzleRuntimeShell({
|
||||
const propKind = propDialog.propKind;
|
||||
setIsPropConfirming(true);
|
||||
setPropConfirmError(null);
|
||||
let useResult: PuzzleRunSnapshot | null | void = null;
|
||||
try {
|
||||
await pauseChangePromiseRef.current;
|
||||
const useResult = await onUseProp?.(propKind);
|
||||
useResult = await onUseProp?.(propKind);
|
||||
if (useResult === null) {
|
||||
return;
|
||||
}
|
||||
@@ -1090,10 +1096,15 @@ export function PuzzleRuntimeShell({
|
||||
setIsOriginalOverlayVisible(true);
|
||||
}
|
||||
if (propKind === 'freezeTime') {
|
||||
setIsFreezeEffectVisible(true);
|
||||
window.setTimeout(() => {
|
||||
setIsFreezeEffectVisible(false);
|
||||
}, 900);
|
||||
// 中文注释:正式 run 可能在冻结确认期间已被服务端结算为失败态;
|
||||
// 这种边界同步只关闭确认窗,不再播放冻结成功反馈。
|
||||
const resultLevel = (useResult ?? null)?.currentLevel ?? currentLevelRef.current;
|
||||
if (resultLevel?.status === 'playing') {
|
||||
setIsFreezeEffectVisible(true);
|
||||
window.setTimeout(() => {
|
||||
setIsFreezeEffectVisible(false);
|
||||
}, 900);
|
||||
}
|
||||
}
|
||||
if (propKind === 'extendTime') {
|
||||
setTimerNowMs(Date.now());
|
||||
|
||||
Reference in New Issue
Block a user