/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; ChromeUtils.defineESModuleGetters(this, { AddonManager: "resource://gre/modules/AddonManager.sys.mjs", ExtensionSettingsStore: "resource://gre/modules/ExtensionSettingsStore.sys.mjs", }); function enableAddon(addon) { return new Promise(resolve => { AddonManager.addAddonListener({ onEnabled(enabledAddon) { if (enabledAddon.id == addon.id) { resolve(); AddonManager.removeAddonListener(this); } }, }); addon.enable(); }); } function disableAddon(addon) { return new Promise(resolve => { AddonManager.addAddonListener({ onDisabled(disabledAddon) { if (disabledAddon.id == addon.id) { resolve(); AddonManager.removeAddonListener(this); } }, }); addon.disable(); }); } add_task(async function test_update_defined_command() { let extension; let updatedExtension; registerCleanupFunction(async () => { await extension.unload(); // updatedExtension might not have started up if we didn't make it that far. if (updatedExtension) { await updatedExtension.unload(); } // Check that ESS is cleaned up on uninstall. let storedCommands = ExtensionSettingsStore.getAllForExtension( extension.id, "commands" ); is(storedCommands.length, 0, "There are no stored commands after unload"); }); extension = ExtensionTestUtils.loadExtension({ useAddonManager: "permanent", manifest: { version: "1.0", browser_specific_settings: { gecko: { id: "commands@mochi.test" } }, commands: { foo: { suggested_key: { default: "Ctrl+Shift+I", }, description: "The foo command", }, }, }, background() { browser.test.onMessage.addListener(async (msg, data) => { if (msg == "update") { await browser.commands.update(data); return browser.test.sendMessage("updateDone"); } else if (msg == "reset") { await browser.commands.reset(data); return browser.test.sendMessage("resetDone"); } else if (msg != "run") { return; } // Test initial manifest command. let commands = await browser.commands.getAll(); browser.test.assertEq(1, commands.length, "There is 1 command"); let command = commands[0]; browser.test.assertEq("foo", command.name, "The name is right"); browser.test.assertEq( "The foo command", command.description, "The description is right" ); browser.test.assertEq( "Ctrl+Shift+I", command.shortcut, "The shortcut is right" ); // Update the shortcut. await browser.commands.update({ name: "foo", shortcut: "Ctrl+Shift+L", }); // Test the updated shortcut. commands = await browser.commands.getAll(); browser.test.assertEq(1, commands.length, "There is still 1 command"); command = commands[0]; browser.test.assertEq("foo", command.name, "The name is unchanged"); browser.test.assertEq( "The foo command", command.description, "The description is unchanged" ); browser.test.assertEq( "Ctrl+Shift+L", command.shortcut, "The shortcut is updated" ); // Update the description. await browser.commands.update({ name: "foo", description: "The only command", }); // Test the updated shortcut. commands = await browser.commands.getAll(); browser.test.assertEq(1, commands.length, "There is still 1 command"); command = commands[0]; browser.test.assertEq("foo", command.name, "The name is unchanged"); browser.test.assertEq( "The only command", command.description, "The description is updated" ); browser.test.assertEq( "Ctrl+Shift+L", command.shortcut, "The shortcut is unchanged" ); // Clear the shortcut. await browser.commands.update({ name: "foo", shortcut: "", }); commands = await browser.commands.getAll(); browser.test.assertEq(1, commands.length, "There is still 1 command"); command = commands[0]; browser.test.assertEq("foo", command.name, "The name is unchanged"); browser.test.assertEq( "The only command", command.description, "The description is unchanged" ); browser.test.assertEq("", command.shortcut, "The shortcut is empty"); // Update the description and shortcut. await browser.commands.update({ name: "foo", description: "The new command", shortcut: " Alt+ Shift +9", }); // Test the updated shortcut. commands = await browser.commands.getAll(); browser.test.assertEq(1, commands.length, "There is still 1 command"); command = commands[0]; browser.test.assertEq("foo", command.name, "The name is unchanged"); browser.test.assertEq( "The new command", command.description, "The description is updated" ); browser.test.assertEq( "Alt+Shift+9", command.shortcut, "The shortcut is updated" ); // Test a bad shortcut update. browser.test.assertThrows( () => browser.commands.update({ name: "foo", shortcut: "Ctl+Shift+L" }), /Type error for parameter detail .+ primary modifier and a key/, "It rejects for a bad shortcut" ); // Try to update a command that doesn't exist. await browser.test.assertRejects( browser.commands.update({ name: "bar", shortcut: "Ctrl+Shift+L" }), 'Unknown command "bar"', "It rejects for an unknown command" ); browser.test.notifyPass("commands"); }); browser.test.sendMessage("ready"); }, }); await extension.startup(); function extensionKeyset(extensionId) { return document.getElementById( makeWidgetId(`ext-keyset-id-${extensionId}`) ); } function checkKey(extensionId, shortcutKey, modifiers) { let keyset = extensionKeyset(extensionId); is(keyset.children.length, 1, "There is 1 key in the keyset"); let key = keyset.children[0]; is(key.getAttribute("key"), shortcutKey, "The key is correct"); is(key.getAttribute("modifiers"), modifiers, "The modifiers are correct"); } function checkNumericKey(extensionId, key, modifiers) { let keyset = extensionKeyset(extensionId); is( keyset.children.length, 2, "There are 2 keys in the keyset now, 1 of which contains a keycode." ); let numpadKey = keyset.children[0]; is( numpadKey.getAttribute("keycode"), `VK_NUMPAD${key}`, "The numpad keycode is correct." ); is( numpadKey.getAttribute("modifiers"), modifiers, "The modifiers are correct" ); let originalNumericKey = keyset.children[1]; is( originalNumericKey.getAttribute("keycode"), `VK_${key}`, "The original key is correct." ); is( originalNumericKey.getAttribute("modifiers"), modifiers, "The modifiers are correct" ); } // Check that the is set for the original shortcut. checkKey(extension.id, "I", "accel,shift"); await extension.awaitMessage("ready"); extension.sendMessage("run"); await extension.awaitFinish("commands"); // Check that the has been updated. checkNumericKey(extension.id, "9", "alt,shift"); // Check that the updated command is stored in ExtensionSettingsStore. let storedCommands = ExtensionSettingsStore.getAllForExtension( extension.id, "commands" ); is(storedCommands.length, 1, "There is only one stored command"); let command = ExtensionSettingsStore.getSetting( "commands", "foo", extension.id ).value; is(command.description, "The new command", "The description is stored"); is(command.shortcut, "Alt+Shift+9", "The shortcut is stored"); // Check that the key is updated immediately. extension.sendMessage("update", { name: "foo", shortcut: "Ctrl+Shift+M" }); await extension.awaitMessage("updateDone"); checkKey(extension.id, "M", "accel,shift"); // Ensure all successive updates are stored. // Force the command to only have a description saved. await ExtensionSettingsStore.addSetting(extension.id, "commands", "foo", { description: "description only", }); // This command now only has a description set in storage, also update the shortcut. extension.sendMessage("update", { name: "foo", shortcut: "Alt+Shift+9" }); await extension.awaitMessage("updateDone"); let storedCommand = await ExtensionSettingsStore.getSetting( "commands", "foo", extension.id ); is( storedCommand.value.shortcut, "Alt+Shift+9", "The shortcut is saved correctly" ); is( storedCommand.value.description, "description only", "The description is saved correctly" ); // Calling browser.commands.reset("foo") should reset to manifest version. extension.sendMessage("reset", "foo"); await extension.awaitMessage("resetDone"); checkKey(extension.id, "I", "accel,shift"); // Check that enable/disable removes the keyset and reloads the saved command. let addon = await AddonManager.getAddonByID(extension.id); await disableAddon(addon); let keyset = extensionKeyset(extension.id); is(keyset, null, "The extension keyset is removed when disabled"); // Add some commands to storage, only "foo" should get loaded. await ExtensionSettingsStore.addSetting(extension.id, "commands", "foo", { shortcut: "Alt+Shift+9", }); await ExtensionSettingsStore.addSetting(extension.id, "commands", "unknown", { shortcut: "Ctrl+Shift+P", }); storedCommands = ExtensionSettingsStore.getAllForExtension( extension.id, "commands" ); is(storedCommands.length, 2, "There are now 2 commands stored"); await enableAddon(addon); // Wait for the keyset to appear (it's async on enable). await TestUtils.waitForCondition(() => extensionKeyset(extension.id)); // The keyset is back with the value from ExtensionSettingsStore. checkNumericKey(extension.id, "9", "alt,shift"); // Check that an update to a shortcut in the manifest is mapped correctly. updatedExtension = ExtensionTestUtils.loadExtension({ useAddonManager: "permanent", manifest: { version: "1.0", browser_specific_settings: { gecko: { id: "commands@mochi.test" } }, commands: { foo: { suggested_key: { default: "Ctrl+Shift+L", }, description: "The foo command", }, }, }, }); await updatedExtension.startup(); await TestUtils.waitForCondition(() => extensionKeyset(extension.id)); // Shortcut is unchanged since it was previously updated. checkNumericKey(extension.id, "9", "alt,shift"); }); add_task(async function updateSidebarCommand() { let extension = ExtensionTestUtils.loadExtension({ useAddonManager: "temporary", manifest: { commands: { _execute_sidebar_action: { suggested_key: { default: "Ctrl+Shift+E", }, }, }, sidebar_action: { default_panel: "sidebar.html", }, }, background() { browser.test.onMessage.addListener(async (msg, data) => { if (msg == "updateShortcut") { await browser.commands.update(data); return browser.test.sendMessage("done"); } throw new Error("Unknown message"); }); }, files: { "sidebar.html": ` A Test Sidebar `, "sidebar.js": function () { window.onload = () => { browser.test.sendMessage("sidebar"); }; }, }, }); await extension.startup(); await extension.awaitMessage("sidebar"); // Show and hide the switcher panel to generate the initial shortcuts. let switcherShown = promisePopupShown(SidebarUI._switcherPanel); SidebarUI.showSwitcherPanel(); await switcherShown; let switcherHidden = promisePopupHidden(SidebarUI._switcherPanel); SidebarUI.hideSwitcherPanel(); await switcherHidden; let buttonId = `button_${makeWidgetId(extension.id)}-sidebar-action`; let button = document.getElementById(buttonId); let shortcut = button.getAttribute("shortcut"); ok(shortcut.endsWith("E"), "The button has the shortcut set"); extension.sendMessage("updateShortcut", { name: "_execute_sidebar_action", shortcut: "Ctrl+Shift+M", }); await extension.awaitMessage("done"); shortcut = button.getAttribute("shortcut"); ok(shortcut.endsWith("M"), "The button shortcut has been updated"); await extension.unload(); });