Files
Genarrative/apps/ai-game-creator-shell/tests/previewZoomKeyboard.test.ts
T
k88936 8c521ca891 移除 UI 预览适配与缩放输入
删除预览工具栏适配按钮、适配回调与对应快捷键
将缩放百分比改为只读显示并移除输入组件及测试
2026-09-10 18:48:56 +08:00

173 lines
5.2 KiB
TypeScript

// @vitest-environment jsdom
import { fireEvent } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
handlePreviewZoomKeyDown,
type PreviewZoomKeyboardActions,
type PreviewZoomKeyboardContext,
previewZoomUsesMetaModifier,
} from '../src/view/ui-editor/components/preview/previewZoomKeyboard';
function createActions(): PreviewZoomKeyboardActions {
return {
resetToActualSize: vi.fn(),
zoomIn: vi.fn(),
zoomOut: vi.fn(),
};
}
function dispatchShortcut({
actions = createActions(),
context = {},
event,
target,
}: {
actions?: PreviewZoomKeyboardActions;
context?: Partial<PreviewZoomKeyboardContext>;
event: KeyboardEventInit;
target?: HTMLElement;
}) {
const resolvedTarget = target ?? document.createElement('div');
document.body.append(resolvedTarget);
const handler = vi.fn((keyboardEvent: KeyboardEvent) =>
handlePreviewZoomKeyDown(
keyboardEvent,
{
hasZoomableViewport: true,
isFocused: false,
isHovered: true,
usesMetaModifier: false,
...context,
},
actions,
),
);
resolvedTarget.addEventListener('keydown', handler);
fireEvent.keyDown(resolvedTarget, event);
const keyboardEvent = handler.mock.calls[0]?.[0];
return { actions, handler, keyboardEvent };
}
afterEach(() => {
document.body.replaceChildren();
});
describe('preview zoom keyboard shortcuts', () => {
it.each([
{ key: '+', code: 'Equal' },
{ key: '=', code: 'Equal' },
{ key: '+', code: 'NumpadAdd' },
])('zooms in for the supported main and numpad keys (%o)', (event) => {
const { actions, keyboardEvent } = dispatchShortcut({
event: { ...event, ctrlKey: true, cancelable: true, repeat: true },
});
expect(actions.zoomIn).toHaveBeenCalledTimes(1);
expect(keyboardEvent?.defaultPrevented).toBe(true);
});
it.each([
{ key: '-', code: 'Minus' },
{ key: '-', code: 'NumpadSubtract' },
])('zooms out for the supported main and numpad keys (%o)', (event) => {
const { actions, keyboardEvent } = dispatchShortcut({
event: { ...event, ctrlKey: true, cancelable: true },
});
expect(actions.zoomOut).toHaveBeenCalledTimes(1);
expect(keyboardEvent?.defaultPrevented).toBe(true);
});
it('does not treat underscore as zoom out', () => {
const { actions, keyboardEvent } = dispatchShortcut({
event: {
key: '_',
code: 'Minus',
ctrlKey: true,
shiftKey: true,
cancelable: true,
},
});
expect(actions.zoomOut).not.toHaveBeenCalled();
expect(keyboardEvent?.defaultPrevented).toBe(false);
});
it('keeps the existing actual-size shortcut', () => {
const { actions } = dispatchShortcut({
event: { key: '1', ctrlKey: true, cancelable: true },
});
expect(actions.resetToActualSize).toHaveBeenCalledTimes(1);
});
it('uses Cmd on Apple platforms and Ctrl elsewhere', () => {
expect(previewZoomUsesMetaModifier('MacIntel')).toBe(true);
expect(previewZoomUsesMetaModifier('iPad')).toBe(true);
expect(previewZoomUsesMetaModifier('Win32')).toBe(false);
const appleActions = createActions();
dispatchShortcut({
actions: appleActions,
context: { usesMetaModifier: true },
event: { key: '=', ctrlKey: true, cancelable: true },
});
expect(appleActions.zoomIn).not.toHaveBeenCalled();
dispatchShortcut({
actions: appleActions,
context: { usesMetaModifier: true },
event: { key: '=', metaKey: true, cancelable: true },
});
expect(appleActions.zoomIn).toHaveBeenCalledTimes(1);
});
it.each([
{ isHovered: false, isFocused: false, hasZoomableViewport: true },
{ isHovered: true, isFocused: false, hasZoomableViewport: false },
])('leaves inactive preview shortcuts to the host (%o)', (context) => {
const { actions, keyboardEvent } = dispatchShortcut({
context,
event: { key: '=', ctrlKey: true, cancelable: true },
});
expect(actions.zoomIn).not.toHaveBeenCalled();
expect(keyboardEvent?.defaultPrevented).toBe(false);
});
it('works while the preview is focused without being hovered', () => {
const { actions } = dispatchShortcut({
context: { isFocused: true, isHovered: false },
event: { key: '=', ctrlKey: true, cancelable: true },
});
expect(actions.zoomIn).toHaveBeenCalledTimes(1);
});
it.each(['input', 'button', 'a'])('ignores interactive %s targets', (tag) => {
const target = document.createElement(tag);
if (target instanceof HTMLAnchorElement) target.href = '#preview';
const { actions, keyboardEvent } = dispatchShortcut({
target,
event: { key: '=', ctrlKey: true, cancelable: true },
});
expect(actions.zoomIn).not.toHaveBeenCalled();
expect(keyboardEvent?.defaultPrevented).toBe(false);
});
it('does not override an event already handled by another control', () => {
const target = document.createElement('div');
target.addEventListener('keydown', (event) => event.preventDefault(), {
once: true,
});
const { actions } = dispatchShortcut({
target,
event: { key: '=', ctrlKey: true, cancelable: true },
});
expect(actions.zoomIn).not.toHaveBeenCalled();
});
});