Files
qiming/qimingclaw/crates/agent-gui-server/tests/desktop/keyboard.test.ts

112 lines
3.1 KiB
TypeScript

/**
* Unit tests for desktop/keyboard.ts — typeText CJK routing, pressKey, hotkey.
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
const mockType = vi.fn();
const mockPressKey = vi.fn();
const mockReleaseKey = vi.fn();
vi.mock('@nut-tree-fork/nut-js', () => ({
keyboard: {
type: mockType,
pressKey: mockPressKey,
releaseKey: mockReleaseKey,
},
Key: {
Enter: 'Enter_Val',
Tab: 'Tab_Val',
Escape: 'Escape_Val',
LeftSuper: 'LeftSuper_Val', // Meta/Command/Cmd alias
LeftControl: 'LeftControl_Val',
LeftAlt: 'LeftAlt_Val',
LeftShift: 'LeftShift_Val',
C: 'C_Val',
V: 'V_Val',
},
}));
const mockPasteText = vi.fn();
vi.mock('../../src/desktop/clipboard.js', () => ({
pasteText: (...args: any[]) => mockPasteText(...args),
}));
import { typeText, pressKey, hotkey } from '../../src/desktop/keyboard.js';
describe('typeText', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('uses nut.js type for short ASCII text', async () => {
await typeText('hello');
expect(mockType).toHaveBeenCalledWith('hello');
expect(mockPasteText).not.toHaveBeenCalled();
});
it('routes CJK text to clipboard paste', async () => {
await typeText('你好世界');
expect(mockPasteText).toHaveBeenCalledWith('你好世界');
expect(mockType).not.toHaveBeenCalled();
});
it('routes non-ASCII text to clipboard paste', async () => {
await typeText('café');
expect(mockPasteText).toHaveBeenCalledWith('café');
expect(mockType).not.toHaveBeenCalled();
});
it('routes long text (>50 chars) to clipboard paste', async () => {
const longText = 'a'.repeat(51);
await typeText(longText);
expect(mockPasteText).toHaveBeenCalledWith(longText);
expect(mockType).not.toHaveBeenCalled();
});
it('uses nut.js type for exactly 50 ASCII chars', async () => {
const text = 'a'.repeat(50);
await typeText(text);
expect(mockType).toHaveBeenCalledWith(text);
expect(mockPasteText).not.toHaveBeenCalled();
});
it('uses nut.js type for empty string', async () => {
await typeText('');
expect(mockType).toHaveBeenCalledWith('');
expect(mockPasteText).not.toHaveBeenCalled();
});
});
describe('pressKey', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('presses and releases a valid key', async () => {
await pressKey('Enter');
expect(mockPressKey).toHaveBeenCalledWith('Enter_Val');
expect(mockReleaseKey).toHaveBeenCalledWith('Enter_Val');
});
it('throws DesktopError for unknown key', async () => {
await expect(pressKey('UnknownKey')).rejects.toThrow('Unknown key: UnknownKey');
});
});
describe('hotkey', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('uses keyboard.type() for hotkey combinations', async () => {
await hotkey(['Meta', 'C']);
// Meta is aliased to LeftSuper
expect(mockType).toHaveBeenCalledWith('LeftSuper_Val', 'C_Val');
});
it('throws DesktopError for unknown key in combination', async () => {
await expect(hotkey(['Meta', 'UnknownKey'])).rejects.toThrow('Unknown key: UnknownKey');
});
});