161 lines
4.2 KiB
TypeScript
161 lines
4.2 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { act, fireEvent, render, screen } from '@testing-library/react';
|
|
import { afterEach, describe, expect, test, vi } from 'vitest';
|
|
|
|
import type { BigFishRuntimeSnapshotResponse } from '../../../packages/shared/src/contracts/bigFish';
|
|
import { BigFishRuntimeShell } from './BigFishRuntimeShell';
|
|
|
|
vi.mock('../ResolvedAssetImage', () => ({
|
|
ResolvedAssetImage: ({
|
|
src,
|
|
alt,
|
|
className,
|
|
}: {
|
|
src?: string | null;
|
|
alt?: string;
|
|
className?: string;
|
|
}) => (src ? <img src={src} alt={alt} className={className} /> : null),
|
|
}));
|
|
|
|
function createRun(
|
|
status: BigFishRuntimeSnapshotResponse['status'],
|
|
): BigFishRuntimeSnapshotResponse {
|
|
return {
|
|
runId: 'big-fish-run-1',
|
|
sessionId: 'big-fish-session-1',
|
|
status,
|
|
tick: 18,
|
|
playerLevel: 2,
|
|
winLevel: 5,
|
|
leaderEntityId: null,
|
|
ownedEntities: [],
|
|
wildEntities: [],
|
|
cameraCenter: { x: 0, y: 0 },
|
|
lastInput: { x: 0, y: 0 },
|
|
eventLog: ['己方鱼群已经耗尽'],
|
|
updatedAt: '2026-04-26T12:00:00.000Z',
|
|
};
|
|
}
|
|
|
|
function dispatchPointerEvent(
|
|
target: HTMLElement,
|
|
type: string,
|
|
options: { pointerId: number; clientX: number; clientY: number },
|
|
) {
|
|
const event = new Event(type, { bubbles: true, cancelable: true });
|
|
Object.assign(event, options);
|
|
target.dispatchEvent(event);
|
|
}
|
|
|
|
describe('BigFishRuntimeShell', () => {
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
test('renders restart and exit actions after a failed run', () => {
|
|
const onBack = vi.fn();
|
|
const onRestart = vi.fn();
|
|
|
|
render(
|
|
<BigFishRuntimeShell
|
|
run={createRun('failed')}
|
|
onBack={onBack}
|
|
onRestart={onRestart}
|
|
onSubmitInput={() => {}}
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: '重来' }));
|
|
fireEvent.click(screen.getByRole('button', { name: '退出' }));
|
|
|
|
expect(screen.getByText('本轮失败')).toBeTruthy();
|
|
expect(onRestart).toHaveBeenCalledTimes(1);
|
|
expect(onBack).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('keeps an exit action after a won run', () => {
|
|
const onBack = vi.fn();
|
|
|
|
render(
|
|
<BigFishRuntimeShell
|
|
run={createRun('won')}
|
|
onBack={onBack}
|
|
onSubmitInput={() => {}}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByText('通关完成')).toBeTruthy();
|
|
expect(screen.queryByRole('button', { name: '重来' })).toBeNull();
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: '退出' }));
|
|
expect(onBack).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('opens and closes the runtime rule modal', () => {
|
|
render(
|
|
<BigFishRuntimeShell
|
|
run={createRun('running')}
|
|
onBack={() => {}}
|
|
onSubmitInput={() => {}}
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: '查看规则' }));
|
|
|
|
expect(screen.getByRole('dialog', { name: '玩法规则' })).toBeTruthy();
|
|
expect(screen.getByText('低级或同级野生实体会被收编。')).toBeTruthy();
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: '关闭' }));
|
|
|
|
expect(screen.queryByRole('dialog', { name: '玩法规则' })).toBeNull();
|
|
});
|
|
|
|
test('keeps moving in the last sampled direction after drag ends', () => {
|
|
vi.useFakeTimers();
|
|
const onSubmitInput = vi.fn();
|
|
|
|
const { container } = render(
|
|
<BigFishRuntimeShell
|
|
run={createRun('running')}
|
|
onBack={() => {}}
|
|
onSubmitInput={onSubmitInput}
|
|
/>,
|
|
);
|
|
const stage = container.querySelector('.touch-none');
|
|
if (!(stage instanceof HTMLElement)) {
|
|
throw new Error('Missing big fish stage');
|
|
}
|
|
|
|
act(() => {
|
|
dispatchPointerEvent(stage, 'pointerdown', {
|
|
pointerId: 1,
|
|
clientX: 100,
|
|
clientY: 100,
|
|
});
|
|
});
|
|
act(() => {
|
|
dispatchPointerEvent(stage, 'pointermove', {
|
|
pointerId: 1,
|
|
clientX: 140,
|
|
clientY: 100,
|
|
});
|
|
});
|
|
act(() => {
|
|
vi.advanceTimersByTime(100);
|
|
});
|
|
act(() => {
|
|
dispatchPointerEvent(stage, 'pointerup', {
|
|
pointerId: 1,
|
|
clientX: 140,
|
|
clientY: 100,
|
|
});
|
|
});
|
|
act(() => {
|
|
vi.advanceTimersByTime(220);
|
|
});
|
|
|
|
expect(onSubmitInput).toHaveBeenLastCalledWith({ x: 1, y: 0 });
|
|
});
|
|
});
|