testkit: key() rejects unlisted multi-char names and shift on printables
commit 2203cbd09dd4ee69b067f88736524d4284baf99c · parent 63181701b8
· browse this tree
Ximianth, 2026-10-10 05:48:25 UTC
key("F1") or key("Up") used to type the letters; key("Backspace") threw a
raw CDP error about the text parameter. Both now reject up front naming
KEYDEFS, which is where a new named key would go.
shift on a printable character sent the unshifted text with the shift bit
held, which no keyboard produces. Rather than silently ignore the option,
reject it: the caller should pass the shifted character. shift stays for
named keys (shift+Tab is what the scenarios use).
Both tests watched failing (resolved undefined) before the fix.
diff --git a/packages/yukey-testkit/src/cdp.test.ts b/packages/yukey-testkit/src/cdp.test.ts index 9eb2b2f..fbb59f5 100644 --- a/packages/yukey-testkit/src/cdp.test.ts +++ b/packages/yukey-testkit/src/cdp.test.ts @@ -90,6 +90,18 @@ describe("Cdp.key", () => { { type: "keyUp", windowsVirtualKeyCode: 65, code: "KeyA", key: "a", modifiers: 0 }, ]); }); + + it("rejects a multi-character name that isn't a known key, sending nothing", async () => { + const sock = new FakeSocket(); + await expect(Cdp.fromSocket(sock).key("F1")).rejects.toThrow(/KEYDEFS/); + expect(sock.sent).toEqual([]); + }); + + it("rejects shift on a printable character (type the shifted character instead)", async () => { + const sock = new FakeSocket(); + await expect(Cdp.fromSocket(sock).key("a", { shift: true })).rejects.toThrow(/shift/); + expect(sock.sent).toEqual([]); + }); }); describe("Cdp.cmd", () => { diff --git a/packages/yukey-testkit/src/cdp.ts b/packages/yukey-testkit/src/cdp.ts index 4f00277..ee47470 100644 --- a/packages/yukey-testkit/src/cdp.ts +++ b/packages/yukey-testkit/src/cdp.ts @@ -125,13 +125,21 @@ export class Cdp { return sent; } - // Dispatch a trusted key press (down + up). Named keys come from KEYDEFS; - // anything else is treated as a printable character. + // Dispatch a trusted key press (down + up). `key` is a DOM KeyboardEvent.key + // value: a named key from KEYDEFS, or a single printable character. + // Shift is only meaningful on named keys (shift+Tab); for a printable + // character, pass the shifted character itself. // Enter and Space carry their text payload on a full keyDown // (rawKeyDown skips text insertion; native widgets need the text to act). async key(key: string, opts: { shift?: boolean } = {}): Promise<void> { const mods = opts.shift === true ? 8 : 0; const def = KEYDEFS[key]; + if (def === undefined && key.length !== 1) { + throw new Error(`key ${JSON.stringify(key)} is not a single character and not in KEYDEFS`); + } + if (def === undefined && mods !== 0) { + throw new Error(`key ${JSON.stringify(key)}: shift applies to named keys only; pass the shifted character`); + } if (def !== undefined) { const [vk, code] = def; const text = key === " " ? " " : key === "Enter" ? "\r" : "";