Skip to content

Commit 5969d8d

Browse files
authored
fix(browser): support non US key input (#6873)
1 parent b01df47 commit 5969d8d

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

packages/browser/src/node/commands/keyboard.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ export const keyboardCleanup: UserEventCommand<(state: KeyboardState) => Promise
7272
}
7373
}
7474

75+
// fallback to insertText for non US key
76+
// https://github.com/microsoft/playwright/blob/50775698ae13642742f2a1e8983d1d686d7f192d/packages/playwright-core/src/server/input.ts#L95
77+
const VALID_KEYS = new Set(['Escape', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'Backquote', '`', '~', 'Digit1', '1', '!', 'Digit2', '2', '@', 'Digit3', '3', '#', 'Digit4', '4', '$', 'Digit5', '5', '%', 'Digit6', '6', '^', 'Digit7', '7', '&', 'Digit8', '8', '*', 'Digit9', '9', '(', 'Digit0', '0', ')', 'Minus', '-', '_', 'Equal', '=', '+', 'Backslash', '\\', '|', 'Backspace', 'Tab', 'KeyQ', 'q', 'Q', 'KeyW', 'w', 'W', 'KeyE', 'e', 'E', 'KeyR', 'r', 'R', 'KeyT', 't', 'T', 'KeyY', 'y', 'Y', 'KeyU', 'u', 'U', 'KeyI', 'i', 'I', 'KeyO', 'o', 'O', 'KeyP', 'p', 'P', 'BracketLeft', '[', '{', 'BracketRight', ']', '}', 'CapsLock', 'KeyA', 'a', 'A', 'KeyS', 's', 'S', 'KeyD', 'd', 'D', 'KeyF', 'f', 'F', 'KeyG', 'g', 'G', 'KeyH', 'h', 'H', 'KeyJ', 'j', 'J', 'KeyK', 'k', 'K', 'KeyL', 'l', 'L', 'Semicolon', ';', ':', 'Quote', '\'', '"', 'Enter', '\n', '\r', 'ShiftLeft', 'Shift', 'KeyZ', 'z', 'Z', 'KeyX', 'x', 'X', 'KeyC', 'c', 'C', 'KeyV', 'v', 'V', 'KeyB', 'b', 'B', 'KeyN', 'n', 'N', 'KeyM', 'm', 'M', 'Comma', ',', '<', 'Period', '.', '>', 'Slash', '/', '?', 'ShiftRight', 'ControlLeft', 'Control', 'MetaLeft', 'Meta', 'AltLeft', 'Alt', 'Space', ' ', 'AltRight', 'AltGraph', 'MetaRight', 'ContextMenu', 'ControlRight', 'PrintScreen', 'ScrollLock', 'Pause', 'PageUp', 'PageDown', 'Insert', 'Delete', 'Home', 'End', 'ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown', 'NumLock', 'NumpadDivide', 'NumpadMultiply', 'NumpadSubtract', 'Numpad7', 'Numpad8', 'Numpad9', 'Numpad4', 'Numpad5', 'Numpad6', 'NumpadAdd', 'Numpad1', 'Numpad2', 'Numpad3', 'Numpad0', 'NumpadDecimal', 'NumpadEnter'])
78+
7579
export async function keyboardImplementation(
7680
pressed: Set<string>,
7781
provider: BrowserProvider,
@@ -91,7 +95,9 @@ export async function keyboardImplementation(
9195
// together, and call `type` once for all non special keys,
9296
// and then `press` for special keys
9397
if (pressed.has(key)) {
94-
await page.keyboard.up(key)
98+
if (VALID_KEYS.has(key)) {
99+
await page.keyboard.up(key)
100+
}
95101
pressed.delete(key)
96102
}
97103

@@ -102,11 +108,18 @@ export async function keyboardImplementation(
102108
}
103109

104110
for (let i = 1; i <= repeat; i++) {
105-
await page.keyboard.down(key)
111+
if (VALID_KEYS.has(key)) {
112+
await page.keyboard.down(key)
113+
}
114+
else {
115+
await page.keyboard.insertText(key)
116+
}
106117
}
107118

108119
if (releaseSelf) {
109-
await page.keyboard.up(key)
120+
if (VALID_KEYS.has(key)) {
121+
await page.keyboard.up(key)
122+
}
110123
}
111124
else {
112125
pressed.add(key)
@@ -116,7 +129,9 @@ export async function keyboardImplementation(
116129

117130
if (!skipRelease && pressed.size) {
118131
for (const key of pressed) {
119-
await page.keyboard.up(key)
132+
if (VALID_KEYS.has(key)) {
133+
await page.keyboard.up(key)
134+
}
120135
}
121136
}
122137
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { expect, test } from 'vitest'
2+
import { userEvent, page, server } from '@vitest/browser/context'
3+
4+
test('non US keys', async () => {
5+
document.body.innerHTML = `
6+
<input placeholder="type-#7396" />
7+
<input placeholder="fill-#7396" />
8+
<input placeholder="type-emoji" />
9+
<input placeholder="fill-emoji" />
10+
`;
11+
12+
await userEvent.type(page.getByPlaceholder("type-#7396"), 'éèù')
13+
await expect.element(page.getByPlaceholder("type-#7396")).toHaveValue('éèù')
14+
await userEvent.fill(page.getByPlaceholder("fill-#7396"), 'éèù')
15+
await expect.element(page.getByPlaceholder("fill-#7396")).toHaveValue('éèù')
16+
17+
// playwright: garbled characters
18+
// webdriverio: error: invalid argument: missing command parameters
19+
// preview: ok
20+
try {
21+
await userEvent.type(page.getByPlaceholder("type-emoji"), '😊😍')
22+
await expect.element(page.getByPlaceholder("type-emoji")).toHaveValue('😊😍')
23+
} catch (e) {
24+
console.error(e)
25+
}
26+
27+
// playwright: ok
28+
// webdriverio: error: ChromeDriver only supports characters in the BMP
29+
// preview: ok
30+
try {
31+
await userEvent.fill(page.getByPlaceholder("fill-emoji"), '😊😍')
32+
await expect.element(page.getByPlaceholder("fill-emoji")).toHaveValue('😊😍')
33+
} catch (e) {
34+
console.error(e)
35+
}
36+
})

test/browser/specs/runner.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ test('user-event', async () => {
147147
"cleanup-retry.test.ts": "pass",
148148
"cleanup1.test.ts": "pass",
149149
"cleanup2.test.ts": "pass",
150+
"keyboard.test.ts": "pass",
150151
}
151152
`)
152153
})

0 commit comments

Comments
 (0)