shortcuts.test.ts

4.0 KB · raw

1// @vitest-environment jsdom23import { describe, it, expect } from "vitest";4import {5  DEFAULT_BINDINGS,6  findConflict,7  formatKeybinding,8  getActiveBindings,9  keybindingFromEvent,10  matchKeybinding,11} from "./shortcuts";1213function ev(key: string, mods: { ctrl?: boolean; meta?: boolean; shift?: boolean; alt?: boolean } = {}): KeyboardEvent {14  return new KeyboardEvent("keydown", {15    key,16    ctrlKey:  Boolean(mods.ctrl),17    metaKey:  Boolean(mods.meta),18    shiftKey: Boolean(mods.shift),19    altKey:   Boolean(mods.alt),20  });21}2223describe("matchKeybinding", () => {24  it("matches case-insensitively on the key letter", () => {25    expect(matchKeybinding(ev("c"), { key: "c" })).toBe(true);26    expect(matchKeybinding(ev("C", { shift: true }), { key: "c", shift: true })).toBe(true);27  });2829  it("requires every modifier to match exactly", () => {30    expect(matchKeybinding(ev("l", { ctrl: true }), { key: "l", ctrl: true })).toBe(true);31    expect(matchKeybinding(ev("l"),                  { key: "l", ctrl: true })).toBe(false);32    expect(matchKeybinding(ev("l", { ctrl: true, shift: true }), { key: "l", ctrl: true })).toBe(false);33  });3435  it("rejects when key differs", () => {36    expect(matchKeybinding(ev("c"), { key: "n" })).toBe(false);37  });38});3940describe("getActiveBindings", () => {41  it("returns full default map when no overrides", () => {42    const active = getActiveBindings(undefined);43    expect(active.copy_password).toEqual(DEFAULT_BINDINGS.copy_password);44    expect(Object.keys(active).length).toBe(Object.keys(DEFAULT_BINDINGS).length);45  });4647  it("user override replaces default for that action only", () => {48    const active = getActiveBindings({ copy_password: { key: "p", ctrl: true } });49    expect(active.copy_password).toEqual({ key: "p", ctrl: true });50    expect(active.copy_username).toEqual(DEFAULT_BINDINGS.copy_username);51  });52});5354describe("keybindingFromEvent", () => {55  it("returns null for bare modifier presses", () => {56    expect(keybindingFromEvent(ev("Shift"))).toBeNull();57    expect(keybindingFromEvent(ev("Control"))).toBeNull();58    expect(keybindingFromEvent(ev("Meta"))).toBeNull();59    expect(keybindingFromEvent(ev("Alt"))).toBeNull();60  });6162  it("captures key + modifiers from the event", () => {63    const b = keybindingFromEvent(ev("k", { ctrl: true, shift: true }));64    expect(b).toEqual({ key: "k", ctrl: true, shift: true });65  });6667  it("omits unset modifier flags rather than storing false", () => {68    const b = keybindingFromEvent(ev("a"));69    expect(b).toEqual({ key: "a" });70  });71});7273describe("formatKeybinding", () => {74  it("uses Ctrl+K style on non-mac", () => {75    expect(formatKeybinding({ key: "k", ctrl: true }, false)).toBe("Ctrl+K");76  });7778  it("uses ⌘ glyph on mac", () => {79    expect(formatKeybinding({ key: "k", meta: true }, true)).toBe("⌘K");80  });8182  it("renames named keys (arrows, escape, enter)", () => {83    expect(formatKeybinding({ key: "ArrowUp" }, false)).toBe("↑");84    expect(formatKeybinding({ key: "Escape" }, false)).toBe("Esc");85    expect(formatKeybinding({ key: "Enter" }, false)).toBe("↵");86    expect(formatKeybinding({ key: " " }, false)).toBe("Space");87  });8889  it("orders mac modifiers ⌃⌥⇧⌘ then key", () => {90    expect(formatKeybinding({ key: "k", ctrl: true, alt: true, shift: true, meta: true }, true))91      .toBe("⌃⌥⇧⌘K");92  });93});9495describe("findConflict", () => {96  it("returns the conflicting action when binding collides", () => {97    const bindings = getActiveBindings({});98    const conflict = findConflict(bindings, { key: "c" });99    expect(conflict).toBe("copy_password");100  });101102  it("excludes the action being rebound from conflict checks", () => {103    const bindings = getActiveBindings({});104    const conflict = findConflict(bindings, { key: "c" }, "copy_password");105    expect(conflict).toBeNull();106  });107108  it("returns null when binding is unique", () => {109    const bindings = getActiveBindings({});110    const conflict = findConflict(bindings, { key: "z", ctrl: true, shift: true });111    expect(conflict).toBeNull();112  });113});