Files
mailflare/tests/hotkey-sequences.test.mjs
Can K.andCan Kirca c105dedd43 Make the "g" navigation shortcuts match reliably (#89)
useHotkeys pushed every keydown into the sequence buffer and only matched when the whole buffer equalled a shortcut. Two things broke that: the Shift keydown of "g" then "!" put "shift" in the buffer (so "g !", go to Spam, never matched), and any key pressed within 800 ms before a sequence (for example "j" and then "g i") left a stale entry in front of it.

Modifier keys no longer enter the buffer, and a sequence now matches when it ends the buffer. A single key still only matches as the whole buffer, so lone shortcuts behave as before. The matching moved to use-hotkeys-utils.ts with a small test.

Co-authored-by: Can Kirca <9063990+cankirca@users.noreply.github.com>
2026-10-11 02:26:08 +07:00

46 lines
1.8 KiB
JavaScript

import assert from "node:assert/strict";
import { mkdtempSync, rmSync } from "node:fs";
import { dirname, join } from "node:path";
import test, { after } from "node:test";
import { fileURLToPath, pathToFileURL } from "node:url";
import { build } from "esbuild";
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
const directory = mkdtempSync(join(root, "node_modules", "mailflare-hotkeys-"));
after(() => rmSync(directory, { recursive: true, force: true }));
await build({
stdin: {
contents: `export { findSequenceMatch, isModifierKey } from "./src/components/shortcuts/use-hotkeys-utils.ts";`,
resolveDir: root,
sourcefile: "hotkey-sequences-entry.ts",
},
outfile: join(directory, "entry.mjs"),
bundle: true,
platform: "node",
format: "esm",
target: "node24",
tsconfig: join(root, "tsconfig.json"),
packages: "external",
logLevel: "silent",
});
const { findSequenceMatch, isModifierKey } = await import(pathToFileURL(join(directory, "entry.mjs")).href);
const shortcuts = [{ key: "g i" }, { key: "g !" }, { key: "e" }];
test("a sequence matches when it ends the buffer", () => {
assert.equal(findSequenceMatch(["g", "i"], shortcuts), shortcuts[0]);
assert.equal(findSequenceMatch(["j", "g", "i"], shortcuts), shortcuts[0]);
assert.equal(findSequenceMatch(["g", "!"], shortcuts), shortcuts[1]);
});
test("a lone key only matches when it is the whole buffer", () => {
assert.equal(findSequenceMatch(["e"], shortcuts), shortcuts[2]);
assert.equal(findSequenceMatch(["j", "e"], shortcuts), undefined);
assert.equal(findSequenceMatch([], shortcuts), undefined);
});
test("modifier keys are not part of a sequence", () => {
for (const key of ["shift", "control", "alt", "meta"]) assert.equal(isModifierKey(key), true);
assert.equal(isModifierKey("g"), false);
});