210 lines
4.9 KiB
TypeScript
210 lines
4.9 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||
|
|
import { renderHook } from "@testing-library/react";
|
||
|
|
import { useKeyboardShortcuts } from "./useKeyboardShortcuts";
|
||
|
|
|
||
|
|
describe("useKeyboardShortcuts", () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.clearAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
vi.restoreAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("triggers callback on matching shortcut", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
const event = new KeyboardEvent("keydown", { key: "k", ctrlKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
|
||
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("does not trigger on non-matching shortcut", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
const event = new KeyboardEvent("keydown", { key: "j", ctrlKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
|
||
|
|
expect(callback).not.toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("respects modifier key requirements", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
shift: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
// Without shift
|
||
|
|
let event = new KeyboardEvent("keydown", { key: "k", ctrlKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
expect(callback).not.toHaveBeenCalled();
|
||
|
|
|
||
|
|
// With shift
|
||
|
|
event = new KeyboardEvent("keydown", {
|
||
|
|
key: "k",
|
||
|
|
ctrlKey: true,
|
||
|
|
shiftKey: true,
|
||
|
|
});
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("handles alt modifier", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
alt: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
const event = new KeyboardEvent("keydown", { key: "k", altKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
|
||
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("skips disabled shortcuts", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
enabled: false,
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
const event = new KeyboardEvent("keydown", { key: "k", ctrlKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
|
||
|
|
expect(callback).not.toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("handles multiple shortcuts", () => {
|
||
|
|
const callback1 = vi.fn();
|
||
|
|
const callback2 = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
callback: callback1,
|
||
|
|
description: "Shortcut 1",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
key: "r",
|
||
|
|
ctrl: true,
|
||
|
|
callback: callback2,
|
||
|
|
description: "Shortcut 2",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
let event = new KeyboardEvent("keydown", { key: "k", ctrlKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
expect(callback1).toHaveBeenCalledTimes(1);
|
||
|
|
expect(callback2).not.toHaveBeenCalled();
|
||
|
|
|
||
|
|
event = new KeyboardEvent("keydown", { key: "r", ctrlKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
expect(callback2).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("prevents default on matched shortcuts", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
const event = new KeyboardEvent("keydown", { key: "k", ctrlKey: true });
|
||
|
|
const preventDefaultSpy = vi.spyOn(event, "preventDefault");
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
|
||
|
|
expect(preventDefaultSpy).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("handles meta key as ctrl on macOS", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
const event = new KeyboardEvent("keydown", { key: "k", metaKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
|
||
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("cleans up event listener on unmount", () => {
|
||
|
|
const callback = vi.fn();
|
||
|
|
const { unmount } = renderHook(() =>
|
||
|
|
useKeyboardShortcuts([
|
||
|
|
{
|
||
|
|
key: "k",
|
||
|
|
ctrl: true,
|
||
|
|
callback,
|
||
|
|
description: "Test shortcut",
|
||
|
|
},
|
||
|
|
])
|
||
|
|
);
|
||
|
|
|
||
|
|
unmount();
|
||
|
|
|
||
|
|
const event = new KeyboardEvent("keydown", { key: "k", ctrlKey: true });
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
|
||
|
|
expect(callback).not.toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
});
|