import test from "node:test"; import assert from "node:assert/strict"; import { initializeShortcut } from "../options/shortcut.js"; function setup(commands) { const elements = Object.fromEntries([ "shortcut-intro", "shortcut-hint", "shortcut-current", "change-shortcut", ].map((id) => [id, Object.assign(new EventTarget(), { textContent: "", hidden: true })])); const document = Object.assign(new EventTarget(), { visibilityState: "visible", getElementById: (id) => elements[id], }); const window = new EventTarget(); const ready = initializeShortcut({ commands, document, window }); return { elements, document, window, ready }; } const flush = () => new Promise((resolve) => setImmediate(resolve)); const command = (shortcut) => ({ name: "ask-chatgpt", description: "Ask ChatGPT", shortcut }); test("shows the configured command rather than another command or the default", async () => { const { elements, ready } = setup({ getAll: async () => [ { name: "other", description: "Other", shortcut: "Alt+O" }, command("Ctrl+Shift+Y"), ] }); await ready; for (const id of ["shortcut-intro", "shortcut-hint", "shortcut-current"]) { assert.match(elements[id].textContent, /Ctrl\+Shift\+Y/); assert.doesNotMatch(elements[id].textContent, /Alt\+Shift\+G|Alt\+O/); } }); test("updates an open page when the shortcut is removed", async () => { let changed; let shortcut = "Alt+Shift+G"; const { elements, ready } = setup({ getAll: async () => [command(shortcut)], onChanged: { addListener: (listener) => { changed = listener; } }, }); await ready; shortcut = ""; changed({ name: "ask-chatgpt", newShortcut: "", oldShortcut: "Alt+Shift+G" }); await flush(); assert.match(elements["shortcut-current"].textContent, /No keyboard shortcut assigned/); assert.doesNotMatch(elements["shortcut-intro"].textContent, /press|Alt\+Shift\+G/i); }); test("refreshes on focus and visibility without the change event API", async () => { let shortcut = "Alt+Shift+G"; const { elements, window, document, ready } = setup({ getAll: async () => [command(shortcut)] }); await ready; shortcut = "Ctrl+Shift+Y"; window.dispatchEvent(new Event("focus")); await flush(); assert.match(elements["shortcut-current"].textContent, /Ctrl\+Shift\+Y/); shortcut = "Alt+J"; document.dispatchEvent(new Event("visibilitychange")); await flush(); assert.match(elements["shortcut-current"].textContent, /Alt\+J/); }); test("missing commands and failed reads never claim the default is assigned", async () => { for (const commands of [undefined, { getAll: async () => [] }, { getAll: async () => { throw new Error("Unavailable"); }, }]) { const { elements, ready } = setup(commands); await ready; assert.doesNotMatch(elements["shortcut-current"].textContent, /Alt\+Shift\+G/); assert.equal(elements["change-shortcut"].hidden, true); } }); test("shortcut editor failure displays manual recovery instructions", async () => { const { elements, ready } = setup({ getAll: async () => [command("Alt+J")], openShortcutSettings: async () => { throw new Error("Unavailable"); }, }); await ready; assert.equal(elements["change-shortcut"].hidden, false); elements["change-shortcut"].dispatchEvent(new Event("click")); await flush(); assert.match(elements["shortcut-current"].textContent, /Manage Extension Shortcuts/); });