import { describe, expect, it } from 'vitest' import { DEFAULT_KEY_BINDINGS, formatKeyBinding, getConflictingShortcutActionIds, isEditableEventTarget, keyBindingFromKeyboardEvent, resolveShortcutScope, SHORTCUT_DEFINITIONS_BY_ID } from '@/lib/keyboardShortcuts' describe ('keyboardShortcuts', () => { it ('defines the default key bindings used by the settings screen', () => { expect (SHORTCUT_DEFINITIONS_BY_ID['global.openShortcutHelp']).toMatchObject ({ label: 'ショートカット一覧を開く', scope: 'global', defaultBinding: { key: '?', shift: true } }) expect (DEFAULT_KEY_BINDINGS['global.focusSearch']).toEqual ({ key: '/' }) expect (DEFAULT_KEY_BINDINGS['navigation.posts']).toEqual ({ key: 'p' }) expect (DEFAULT_KEY_BINDINGS['pagination.next']).toEqual ({ key: 'ArrowRight' }) expect (DEFAULT_KEY_BINDINGS['settings.theme']).toEqual ({ key: '3' }) }) it ('formats key bindings for display', () => { expect (formatKeyBinding ({ key: '?', shift: true })).toBe ('Shift + ?') expect (formatKeyBinding ({ key: '/' })).toBe ('/') expect (formatKeyBinding ({ key: 'p' })).toBe ('P') expect (formatKeyBinding ({ key: 'ArrowRight' })).toBe ('ArrowRight') expect (formatKeyBinding (null)).toBe ('未割当') }) it ('normalises keyboard events without assigning space by default', () => { const event = { key: 'P', ctrlKey: false, shiftKey: false, altKey: false, metaKey: false } as KeyboardEvent expect (keyBindingFromKeyboardEvent (event)).toEqual ({ key: 'p' }) expect (DEFAULT_KEY_BINDINGS['pagination.next']).not.toEqual ({ key: ' ' }) }) it ('detects conflicting action bindings', () => { const conflicts = getConflictingShortcutActionIds ({ ...DEFAULT_KEY_BINDINGS, 'navigation.posts': { key: 'p' }, 'navigation.tags': { key: 'p' } }) expect (conflicts.has ('navigation.posts')).toBe (true) expect (conflicts.has ('navigation.tags')).toBe (true) expect (conflicts.has ('navigation.wiki')).toBe (false) }) it ('resolves route scopes and editable event targets', () => { const input = document.createElement ('input') const div = document.createElement ('div') div.setAttribute ('role', 'textbox') expect (resolveShortcutScope ('/posts/search')).toBe ('postSearch') expect (resolveShortcutScope ('/users/settings')).toBe ('settings') expect (resolveShortcutScope ('/materials/1')).toBe ('materials') expect (isEditableEventTarget (input)).toBe (true) expect (isEditableEventTarget (div)).toBe (true) expect (isEditableEventTarget (document.createElement ('button'))).toBe (false) }) })