Skip to content

Commit 591a5ce

Browse files
committed
fix(keyboard): parse escaped bracket followed by descriptor
1 parent 2c5d9f1 commit 591a5ce

File tree

3 files changed

+71
-35
lines changed

3 files changed

+71
-35
lines changed

src/utils/keyDef/readNextDescriptor.ts

+8-10
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,7 @@ export function readNextDescriptor(text: string) {
2121

2222
pos += startBracket.length
2323

24-
// `foo{{bar` is an escaped char at position 3,
25-
// but `foo{{{>5}bar` should be treated as `{` pressed down for 5 keydowns.
26-
const startBracketRepeated = startBracket
27-
? (text.match(new RegExp(`^\\${startBracket}+`)) as RegExpMatchArray)[0]
28-
.length
29-
: 0
30-
const isEscapedChar =
31-
startBracketRepeated === 2 ||
32-
(startBracket === '{' && startBracketRepeated > 3)
24+
const isEscapedChar = new RegExp(`^\\${startBracket}{2}`).test(text)
3325

3426
const type = isEscapedChar ? '' : startBracket
3527

@@ -64,7 +56,13 @@ function readTag(
6456

6557
pos += releasePreviousModifier.length
6658

67-
const descriptor = text.slice(pos).match(/^\w+/)?.[0]
59+
const escapedDescriptor = startBracket === '{' && text[pos] === '\\'
60+
61+
pos += Number(escapedDescriptor)
62+
63+
const descriptor = escapedDescriptor
64+
? text[pos]
65+
: text.slice(pos).match(startBracket === '{' ? /^\w+|^[^}>/]/ : /^\w+/)?.[0]
6866

6967
assertDescriptor(descriptor, text, pos)
7068

tests/keyboard/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ it('type asynchronous', async () => {
7878
})
7979

8080
it('error in async', async () => {
81-
await expect(userEvent.keyboard('{!', {delay: 1})).rejects.toThrowError(
82-
'Expected key descriptor but found "!" in "{!"',
81+
await expect(userEvent.keyboard('[!', {delay: 1})).rejects.toThrowError(
82+
'Expected key descriptor but found "!" in "[!"',
8383
)
8484
})
8585

tests/keyboard/parseKeyDef.ts

+61-23
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,66 @@ import {keyboardKey} from '#src/keyboard/types'
55

66
cases(
77
'reference key per',
8-
({text, key, code}) => {
8+
({text, keyDef}) => {
99
const parsed = parseKeyDef(defaultKeyMap, `/${text}/`)
10-
expect(parsed).toHaveLength(3)
11-
expect(parsed[1]).toEqual({
12-
keyDef: expect.objectContaining({
13-
key,
14-
code,
15-
}) as keyboardKey,
16-
releasePrevious: false,
17-
releaseSelf: true,
18-
repeat: 1,
19-
})
10+
keyDef = Array.isArray(keyDef) ? keyDef : [keyDef]
11+
expect(parsed).toHaveLength(2 + keyDef.length)
12+
expect(parsed.slice(1, -1)).toEqual(
13+
keyDef.map(d =>
14+
expect.objectContaining({
15+
keyDef: expect.objectContaining(d) as keyboardKey,
16+
}),
17+
),
18+
)
2019
},
2120
{
22-
code: {text: '[ControlLeft]', key: 'Control', code: 'ControlLeft'},
23-
'unimplemented code': {text: '[Foo]', key: 'Unknown', code: 'Foo'},
24-
key: {text: '{Control}', key: 'Control', code: 'ControlLeft'},
25-
'unimplemented key': {text: '{Foo}', key: 'Foo', code: 'Unknown'},
26-
'printable character': {text: 'a', key: 'a', code: 'KeyA'},
27-
'modifiers as printable characters': {text: '/', key: '/', code: 'Unknown'},
28-
'{ as printable': {text: '{{', key: '{', code: 'Unknown'},
29-
'[ as printable': {text: '[[', key: '[', code: 'Unknown'},
21+
code: {
22+
text: '[ControlLeft]',
23+
keyDef: {key: 'Control', code: 'ControlLeft'},
24+
},
25+
'unimplemented code': {
26+
text: '[Foo]',
27+
keyDef: {key: 'Unknown', code: 'Foo'},
28+
},
29+
key: {
30+
text: '{Control}',
31+
keyDef: {key: 'Control', code: 'ControlLeft'},
32+
},
33+
'unimplemented key': {
34+
text: '{Foo}',
35+
keyDef: {key: 'Foo', code: 'Unknown'},
36+
},
37+
'printable character': {
38+
text: 'a',
39+
keyDef: {key: 'a', code: 'KeyA'},
40+
},
41+
'modifiers as printable characters': {
42+
text: '/',
43+
keyDef: {key: '/', code: 'Unknown'},
44+
},
45+
'{ as printable': {
46+
text: '{{',
47+
keyDef: {key: '{', code: 'Unknown'},
48+
},
49+
'{ as printable followed by descriptor': {
50+
text: '{{{foo}',
51+
keyDef: [
52+
{key: '{', code: 'Unknown'},
53+
{key: 'foo', code: 'Unknown'},
54+
],
55+
},
56+
'{ as key with modifiers': {
57+
text: '{\\{>5/}',
58+
keyDef: {key: '{', code: 'Unknown'},
59+
},
60+
'modifier as key with modifiers': {
61+
text: '{/\\/>5/}',
62+
keyDef: {key: '/', code: 'Unknown'},
63+
},
64+
'[ as printable': {
65+
text: '[[',
66+
keyDef: {key: '[', code: 'Unknown'},
67+
},
3068
},
3169
)
3270

@@ -79,10 +117,6 @@ cases(
79117
expect(() => parseKeyDef(defaultKeyMap, `${text}`)).toThrow(expectedError)
80118
},
81119
{
82-
'invalid descriptor': {
83-
text: '{!}',
84-
expectedError: 'but found "!" in "{!}"',
85-
},
86120
'missing descriptor': {
87121
text: '',
88122
expectedError: 'but found "" in ""',
@@ -99,5 +133,9 @@ cases(
99133
text: '{a>3)',
100134
expectedError: 'but found ")" in "{a>3)"',
101135
},
136+
'unescaped modifier': {
137+
text: '{/>5}',
138+
expectedError: 'but found ">" in "{/>5}"',
139+
},
102140
},
103141
)

0 commit comments

Comments
 (0)