Skip to content

Commit e503ab7

Browse files
author
amaher
committed
test(defineShortcuts): add tests for single keys, chains, and layout-independent mode
1 parent 9cb37ce commit e503ab7

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

src/runtime/composables/defineShortcuts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export function defineShortcuts(config: MaybeRef<ShortcutsConfig>, options: Shor
125125

126126
// push either code or key depending on layoutIndependent flag
127127
chainedInputs.value.push(layoutIndependent ? e.code : e.key)
128-
128+
129129
// try matching a chained shortcut
130130
if (chainedInputs.value.length >= 2) {
131131
chainedKey = chainedInputs.value.slice(-2).join('-')
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest'
2+
import { defineShortcuts } from '../../src/runtime/composables/defineShortcuts'
3+
4+
describe('defineShortcuts', () => {
5+
let handlers: Record<string, ReturnType<typeof vi.fn>>
6+
7+
beforeEach(() => {
8+
handlers = {
9+
'f': vi.fn(),
10+
'h': vi.fn(),
11+
'f-h': vi.fn(),
12+
'z-x': vi.fn(),
13+
'meta_k': vi.fn()
14+
}
15+
})
16+
17+
function createShortcuts(options: any = {}) {
18+
defineShortcuts(
19+
{
20+
'f': handlers.f,
21+
'h': handlers.h,
22+
'f-h': handlers['f-h'],
23+
'z-x': handlers['z-x'],
24+
'meta_k': handlers['meta_k']
25+
},
26+
options
27+
)
28+
}
29+
30+
function dispatchKey(key: string, code?: string) {
31+
const e = new KeyboardEvent('keydown', {
32+
key,
33+
code: code || `Key${key.toUpperCase()}`,
34+
bubbles: true
35+
})
36+
window.dispatchEvent(e)
37+
}
38+
39+
it('fires single key shortcuts', async () => {
40+
createShortcuts({ chainDelay: 50 })
41+
42+
dispatchKey('f')
43+
await new Promise(r => setTimeout(r, 60))
44+
45+
expect(handlers.f).toHaveBeenCalled()
46+
expect(handlers['f-h']).not.toHaveBeenCalled()
47+
})
48+
49+
it('fires chain shortcuts if second key pressed', async () => {
50+
createShortcuts({ chainDelay: 50 })
51+
52+
dispatchKey('f')
53+
dispatchKey('h')
54+
await new Promise(r => setTimeout(r, 60))
55+
56+
expect(handlers['f-h']).toHaveBeenCalled()
57+
expect(handlers.f).not.toHaveBeenCalled()
58+
})
59+
60+
it('fires z-x chain independently', async () => {
61+
createShortcuts({ chainDelay: 50 })
62+
63+
dispatchKey('z')
64+
dispatchKey('x')
65+
await new Promise(r => setTimeout(r, 60))
66+
67+
expect(handlers['z-x']).toHaveBeenCalled()
68+
})
69+
70+
it('fires h alone if pressed independently', async () => {
71+
createShortcuts({ chainDelay: 50 })
72+
73+
dispatchKey('h')
74+
await new Promise(r => setTimeout(r, 60))
75+
76+
expect(handlers.h).toHaveBeenCalled()
77+
})
78+
79+
it('works across different keyboard layouts when layoutIndependent is enabled', async () => {
80+
createShortcuts({ chainDelay: 50, layoutIndependent: true })
81+
82+
// Press a different key character on the same physical key
83+
dispatchKey('ب', 'KeyF') // 'ب' is what Arabic layout produces on the F key
84+
await new Promise(r => setTimeout(r, 60))
85+
86+
expect(handlers.f).toHaveBeenCalled()
87+
})
88+
})

0 commit comments

Comments
 (0)