Files
openmaic/OpenMAIC/packages/@openmaic/editor/test/react/useCanvasShortcuts.test.ts
2026-08-16 14:58:47 +08:00

116 lines
3.4 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest';
import { handleCanvasShortcut, type CanvasCommands } from '../../src/react';
function commands(): CanvasCommands {
return {
clearSelection: vi.fn(),
selectAll: vi.fn(),
deleteSelection: vi.fn(),
lockSelection: vi.fn(),
copySelection: vi.fn(),
cutSelection: vi.fn(),
pasteElements: vi.fn(),
unlockTarget: vi.fn(),
toggleGroup: vi.fn(),
reorderTarget: vi.fn(),
alignSelection: vi.fn(),
};
}
function keyEvent(
key: string,
options: {
ctrlKey?: boolean;
metaKey?: boolean;
altKey?: boolean;
repeat?: boolean;
target?: unknown;
} = {},
) {
return {
key,
ctrlKey: options.ctrlKey ?? false,
metaKey: options.metaKey ?? false,
altKey: options.altKey ?? false,
repeat: options.repeat ?? false,
target: options.target ?? null,
preventDefault: vi.fn(),
};
}
describe('handleCanvasShortcut', () => {
it.each([
['Delete', 'deleteSelection'],
['Backspace', 'deleteSelection'],
['Escape', 'clearSelection'],
] as const)('maps %s to %s', (key, command) => {
const available = commands();
const event = keyEvent(key);
expect(handleCanvasShortcut(event, available)).toBe(true);
expect(available[command]).toHaveBeenCalledOnce();
expect(event.preventDefault).toHaveBeenCalledOnce();
});
it.each([
['a', 'selectAll'],
['c', 'copySelection'],
['x', 'cutSelection'],
['v', 'pasteElements'],
['l', 'lockSelection'],
['g', 'toggleGroup'],
] as const)('maps Ctrl/Cmd+%s to %s', (key, command) => {
for (const modifier of [{ ctrlKey: true }, { metaKey: true }]) {
const available = commands();
const event = keyEvent(key, modifier);
expect(handleCanvasShortcut(event, available)).toBe(true);
expect(available[command]).toHaveBeenCalledOnce();
expect(event.preventDefault).toHaveBeenCalledOnce();
}
});
it.each([
{ tagName: 'INPUT' },
{ tagName: 'TEXTAREA' },
{ tagName: 'SELECT' },
{ tagName: 'DIV', isContentEditable: true },
{
tagName: 'DIV',
closest: (selector: string) => (selector.includes('ProseMirror') ? {} : null),
},
])('ignores editable targets', (target) => {
const available = commands();
const event = keyEvent('Delete', { target });
expect(handleCanvasShortcut(event, available)).toBe(false);
expect(available.deleteSelection).not.toHaveBeenCalled();
expect(event.preventDefault).not.toHaveBeenCalled();
});
it.each([
['pick mode', { pickActive: true }],
['disabled shortcuts', { enabled: false }],
] as const)('ignores shortcuts during %s', (_label, options) => {
const available = commands();
const event = keyEvent('Delete');
expect(handleCanvasShortcut(event, available, options)).toBe(false);
expect(available.deleteSelection).not.toHaveBeenCalled();
expect(event.preventDefault).not.toHaveBeenCalled();
});
it('ignores unmodified letters, Alt combinations, and keyboard auto-repeat', () => {
for (const event of [
keyEvent('a'),
keyEvent('g', { ctrlKey: true, altKey: true }),
keyEvent('g', { ctrlKey: true, repeat: true }),
]) {
const available = commands();
expect(handleCanvasShortcut(event, available)).toBe(false);
expect(available.toggleGroup).not.toHaveBeenCalled();
expect(event.preventDefault).not.toHaveBeenCalled();
}
});
});