// @vitest-environment happy-dom import { describe, expect, it, vi } from 'vitest'; import { createHotkeys, isTypingTarget } from './hotkeys'; /** The half of hotkeys.ts that needs a real window: attach/detach and typing guards. */ describe('createHotkeys attach/detach', () => { it('routes real window keydown events once attached', () => { const keys = createHotkeys(); const hit = vi.fn(); keys.bind('r', hit); keys.attach(); window.dispatchEvent(new KeyboardEvent('keydown', { key: 'r' })); expect(hit).toHaveBeenCalledTimes(1); keys.detach(); }); it('stops routing after detach — no listener left on the window', () => { const keys = createHotkeys(); const hit = vi.fn(); keys.bind('r', hit); keys.attach(); keys.detach(); window.dispatchEvent(new KeyboardEvent('keydown', { key: 'r' })); expect(hit).not.toHaveBeenCalled(); }); it('ignores keys bound before attach until attach is called', () => { const keys = createHotkeys(); const hit = vi.fn(); keys.bind('x', hit); window.dispatchEvent(new KeyboardEvent('keydown', { key: 'x' })); expect(hit).not.toHaveBeenCalled(); keys.attach(); window.dispatchEvent(new KeyboardEvent('keydown', { key: 'x' })); expect(hit).toHaveBeenCalledTimes(1); keys.detach(); }); it('calls preventDefault on space so the page never scrolls under the factory', () => { const keys = createHotkeys(); keys.bind(' ', () => {}); keys.attach(); const ev = new KeyboardEvent('keydown', { key: ' ', cancelable: true }); window.dispatchEvent(ev); expect(ev.defaultPrevented).toBe(true); keys.detach(); }); it('does not fire a hotkey while the player is typing in a field', () => { const keys = createHotkeys(); const hit = vi.fn(); keys.bind('r', hit); keys.attach(); const input = document.createElement('input'); document.body.append(input); input.dispatchEvent(new KeyboardEvent('keydown', { key: 'r', bubbles: true })); expect(hit).not.toHaveBeenCalled(); input.remove(); keys.detach(); }); }); describe('isTypingTarget', () => { it('is true for form fields and contenteditable, false for the world', () => { for (const tag of ['input', 'textarea', 'select']) { expect(isTypingTarget(document.createElement(tag))).toBe(true); } const div = document.createElement('div'); expect(isTypingTarget(div)).toBe(false); // The inspector's recipe