236 lines
7.4 KiB
TypeScript
236 lines
7.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
findKeybindingConflicts,
|
|
formatKeybindingList,
|
|
getEffectiveKeybindingsForAction,
|
|
keybindingFromInput,
|
|
keybindingFromInputForAction,
|
|
keybindingMatchesAction,
|
|
normalizeKeybinding,
|
|
normalizeKeybindingListForAction,
|
|
normalizeKeybindingList
|
|
} from './keybindings'
|
|
|
|
describe('keybindings', () => {
|
|
it('normalizes editable shortcut input and rejects unsafe bindings', () => {
|
|
expect(normalizeKeybinding(' ctrl + shift + p ')).toEqual({
|
|
ok: true,
|
|
value: 'Ctrl+Shift+P'
|
|
})
|
|
expect(normalizeKeybinding('shift+insert')).toEqual({ ok: true, value: 'Shift+Insert' })
|
|
expect(normalizeKeybinding('cmdorctrl+p')).toEqual({ ok: true, value: 'Mod+P' })
|
|
expect(normalizeKeybindingList('Ctrl+Shift+P, ctrl+shift+p, ⌘+k')).toEqual([
|
|
'Ctrl+Shift+P',
|
|
'Cmd+K'
|
|
])
|
|
|
|
expect(normalizeKeybinding('Shift+P')).toMatchObject({ ok: false })
|
|
expect(normalizeKeybinding('Mod+Ctrl+P')).toMatchObject({ ok: false })
|
|
expect(normalizeKeybinding('Ctrl+Nope')).toMatchObject({ ok: false })
|
|
})
|
|
|
|
it('allows safe bare keys only for scoped actions that opt in', () => {
|
|
expect(normalizeKeybinding('Delete')).toMatchObject({ ok: false })
|
|
expect(normalizeKeybindingListForAction('fileExplorer.delete', 'Delete')).toEqual(['Delete'])
|
|
expect(normalizeKeybindingListForAction('fileExplorer.delete', 'x')).toMatchObject({
|
|
ok: false
|
|
})
|
|
})
|
|
|
|
it('captures key events into canonical editable shortcuts', () => {
|
|
expect(
|
|
keybindingFromInput(
|
|
{ key: 'j', code: 'KeyJ', meta: true, control: false, alt: false, shift: false },
|
|
'darwin'
|
|
)
|
|
).toEqual({ ok: true, value: 'Mod+J' })
|
|
expect(
|
|
keybindingFromInput(
|
|
{ key: 'J', code: 'KeyJ', control: true, meta: false, alt: true, shift: true },
|
|
'linux'
|
|
)
|
|
).toEqual({ ok: true, value: 'Mod+Alt+Shift+J' })
|
|
expect(
|
|
keybindingFromInput({ key: 'Control', code: 'ControlLeft', control: true }, 'linux')
|
|
).toEqual({ ok: false, error: 'Press a key, not only a modifier.' })
|
|
})
|
|
|
|
it('applies per-action bare-key rules while capturing shortcuts', () => {
|
|
const deleteEvent = {
|
|
key: 'Delete',
|
|
code: 'Delete',
|
|
control: false,
|
|
meta: false,
|
|
alt: false,
|
|
shift: false
|
|
}
|
|
|
|
expect(keybindingFromInput(deleteEvent, 'linux')).toMatchObject({ ok: false })
|
|
expect(keybindingFromInputForAction('fileExplorer.delete', deleteEvent, 'linux')).toEqual({
|
|
ok: true,
|
|
value: 'Delete'
|
|
})
|
|
})
|
|
|
|
it('formats keybindings with platform labels', () => {
|
|
expect(formatKeybindingList(['Mod+Shift+J'], 'darwin')).toBe('⌘⇧J')
|
|
expect(formatKeybindingList(['Mod+Shift+J'], 'linux')).toBe('Ctrl+Shift+J')
|
|
expect(formatKeybindingList([], 'win32')).toBe('Unassigned')
|
|
})
|
|
|
|
it('uses overrides as the complete effective binding list for an action', () => {
|
|
const overrides = {
|
|
'worktree.quickOpen': ['Ctrl+Alt+O', 'not-a-shortcut']
|
|
}
|
|
|
|
expect(getEffectiveKeybindingsForAction('worktree.quickOpen', 'linux', overrides)).toEqual([
|
|
'Ctrl+Alt+O'
|
|
])
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'worktree.quickOpen',
|
|
{ key: 'o', code: 'KeyO', control: true, meta: false, alt: true, shift: false },
|
|
'linux',
|
|
overrides
|
|
)
|
|
).toBe(true)
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'worktree.quickOpen',
|
|
{ key: 'p', code: 'KeyP', control: true, meta: false, alt: false, shift: false },
|
|
'linux',
|
|
overrides
|
|
)
|
|
).toBe(false)
|
|
})
|
|
|
|
it('reports conflicts across default and customized actions', () => {
|
|
expect(findKeybindingConflicts('linux')).toEqual([])
|
|
|
|
const conflicts = findKeybindingConflicts('linux', { 'view.tasks': ['Mod+P'] })
|
|
|
|
expect(conflicts).toContainEqual({
|
|
binding: 'Mod+P',
|
|
actionIds: expect.arrayContaining(['worktree.quickOpen', 'view.tasks'])
|
|
})
|
|
})
|
|
|
|
it('reports customized renderer conflicts with native menu accelerators', () => {
|
|
expect(findKeybindingConflicts('darwin')).toEqual([])
|
|
|
|
const conflicts = findKeybindingConflicts('darwin', {
|
|
'worktree.palette': ['Mod+Shift+E']
|
|
})
|
|
|
|
expect(conflicts).toContainEqual({
|
|
binding: 'Mod+Shift+E',
|
|
actionIds: expect.arrayContaining([
|
|
'file.exportPdf',
|
|
'sidebar.explorer.toggle',
|
|
'worktree.palette'
|
|
])
|
|
})
|
|
})
|
|
|
|
it('keeps Orca-first terminal context backward compatible', () => {
|
|
const ctrlP = {
|
|
key: 'p',
|
|
code: 'KeyP',
|
|
control: true,
|
|
meta: false,
|
|
alt: false,
|
|
shift: false
|
|
}
|
|
|
|
expect(keybindingMatchesAction('worktree.quickOpen', ctrlP, 'linux')).toBe(true)
|
|
expect(
|
|
keybindingMatchesAction('worktree.quickOpen', ctrlP, 'linux', undefined, {
|
|
context: 'terminal',
|
|
terminalShortcutPolicy: 'orca-first'
|
|
})
|
|
).toBe(true)
|
|
expect(
|
|
keybindingMatchesAction('worktree.quickOpen', ctrlP, 'linux', undefined, {
|
|
context: 'terminal',
|
|
terminalShortcutPolicy: 'terminal-first'
|
|
})
|
|
).toBe(false)
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'terminal.search',
|
|
{ key: 'f', code: 'KeyF', control: true, meta: false, alt: false, shift: false },
|
|
'linux',
|
|
undefined,
|
|
{ context: 'terminal', terminalShortcutPolicy: 'terminal-first' }
|
|
)
|
|
).toBe(true)
|
|
})
|
|
|
|
it('keeps terminal-allowed app shortcuts active in terminal-first mode', () => {
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'floatingTerminal.toggle',
|
|
{ key: 't', code: 'KeyT', control: true, meta: false, alt: true, shift: false },
|
|
'linux',
|
|
undefined,
|
|
{ context: 'terminal', terminalShortcutPolicy: 'terminal-first' }
|
|
)
|
|
).toBe(true)
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'tab.previousRecent',
|
|
{ key: 'Tab', code: 'Tab', control: true, meta: false, alt: false, shift: false },
|
|
'linux',
|
|
undefined,
|
|
{ context: 'terminal', terminalShortcutPolicy: 'terminal-first' }
|
|
)
|
|
).toBe(true)
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'worktree.palette',
|
|
{ key: 'j', code: 'KeyJ', control: false, meta: true, alt: false, shift: false },
|
|
'darwin',
|
|
undefined,
|
|
{ context: 'app', terminalShortcutPolicy: 'terminal-first' }
|
|
)
|
|
).toBe(true)
|
|
})
|
|
|
|
it('keeps the existing terminal paste defaults on Windows and Linux', () => {
|
|
expect(getEffectiveKeybindingsForAction('terminal.paste', 'darwin')).toEqual(['Mod+V'])
|
|
expect(getEffectiveKeybindingsForAction('terminal.paste', 'linux')).toEqual([
|
|
'Ctrl+V',
|
|
'Ctrl+Shift+V',
|
|
'Shift+Insert'
|
|
])
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'terminal.paste',
|
|
{ key: 'v', code: 'KeyV', control: true, meta: false, alt: false, shift: false },
|
|
'linux'
|
|
)
|
|
).toBe(true)
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'terminal.paste',
|
|
{ key: 'Insert', code: 'Insert', control: false, meta: false, alt: false, shift: true },
|
|
'linux'
|
|
)
|
|
).toBe(true)
|
|
})
|
|
|
|
it('matches the default file explorer delete shortcut', () => {
|
|
expect(getEffectiveKeybindingsForAction('fileExplorer.delete', 'darwin')).toEqual([
|
|
'Mod+Backspace',
|
|
'Delete'
|
|
])
|
|
expect(
|
|
keybindingMatchesAction(
|
|
'fileExplorer.delete',
|
|
{ key: 'Delete', code: 'Delete', control: false, meta: false, alt: false, shift: false },
|
|
'linux'
|
|
)
|
|
).toBe(true)
|
|
})
|
|
})
|