返回 CodeWhale
slash-shortcut.test.ts
根目录 / web / lib / slash-shortcut.test.ts
1 import { describe, expect, it } from "vitest";
2 import { isSlashShortcut, type ShortcutKeyEvent } from "./slash-shortcut";
3
4 function key(overrides: Partial<ShortcutKeyEvent> = {}): ShortcutKeyEvent {
5 return {
6 key: "/",
7 ctrlKey: false,
8 metaKey: false,
9 altKey: false,
10 isComposing: false,
11 target: { tagName: "BODY", isContentEditable: false },
12 ...overrides,
13 };
14 }
15
16 describe("isSlashShortcut (WCAG 2.1.4 character key shortcut)", () => {
17 it("fires for an unmodified slash typed outside a field", () => {
18 expect(isSlashShortcut(key())).toBe(true);
19 expect(isSlashShortcut(key({ target: null }))).toBe(true);
20 });
21
22 it("ignores other keys", () => {
23 expect(isSlashShortcut(key({ key: "?" }))).toBe(false);
24 });
25
26 it("ignores modified keys and IME composition", () => {
27 expect(isSlashShortcut(key({ ctrlKey: true }))).toBe(false);
28 expect(isSlashShortcut(key({ metaKey: true }))).toBe(false);
29 expect(isSlashShortcut(key({ altKey: true }))).toBe(false);
30 expect(isSlashShortcut(key({ isComposing: true }))).toBe(false);
31 });
32
33 it.each(["INPUT", "TEXTAREA", "SELECT", "textarea"])("leaves typing in a %s alone", (tagName) => {
34 expect(isSlashShortcut(key({ target: { tagName } }))).toBe(false);
35 });
36
37 it("leaves typing in contenteditable content alone", () => {
38 expect(isSlashShortcut(key({ target: { tagName: "DIV", isContentEditable: true } }))).toBe(false);
39 });
40
41 it("leaves a key an inner widget already handled alone", () => {
42 expect(isSlashShortcut(key({ defaultPrevented: true }))).toBe(false);
43 });
44
45 it.each(["textbox", "searchbox", "combobox", " TextBox "])("leaves typing in a role=%s widget alone", (role) => {
46 const target = { tagName: "DIV", getAttribute: (name: string) => (name === "role" ? role : null) };
47 expect(isSlashShortcut(key({ target }))).toBe(false);
48 });
49
50 it("still fires over a role that is not a text widget", () => {
51 const target = { tagName: "DIV", getAttribute: (name: string) => (name === "role" ? "button" : null) };
52 expect(isSlashShortcut(key({ target }))).toBe(true);
53 });
54
55 it("looks through a shadow root to the element that received the key", () => {
56 const host = { tagName: "MY-EDITOR" };
57 const inner = { tagName: "INPUT" };
58 expect(isSlashShortcut(key({ target: host, composedPath: () => [inner, host] }))).toBe(false);
59 expect(isSlashShortcut(key({ target: host, composedPath: () => [host] }))).toBe(true);
60 });
61 });
62
62 lines TYPESCRIPT