diff options
Diffstat (limited to 'toolkit/mozapps/extensions/test/browser/browser_manage_shortcuts.js')
-rw-r--r-- | toolkit/mozapps/extensions/test/browser/browser_manage_shortcuts.js | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/browser/browser_manage_shortcuts.js b/toolkit/mozapps/extensions/test/browser/browser_manage_shortcuts.js new file mode 100644 index 0000000000..aee47dd049 --- /dev/null +++ b/toolkit/mozapps/extensions/test/browser/browser_manage_shortcuts.js @@ -0,0 +1,331 @@ +"use strict"; + +const { PromiseTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromiseTestUtils.sys.mjs" +); +PromiseTestUtils.allowMatchingRejectionsGlobally( + /Message manager disconnected/ +); + +function extensionShortcutsReady(id) { + let extension = WebExtensionPolicy.getByID(id).extension; + return BrowserTestUtils.waitForCondition(() => { + return extension.shortcuts.keysetsMap.has(window); + }, "Wait for add-on keyset to be registered"); +} + +async function loadShortcutsView() { + // Load the theme view initially so we can verify that the category is switched + // to "extension" when the shortcuts view is loaded. + let win = await loadInitialView("theme"); + let categoryUtils = new CategoryUtilities(win); + + is( + categoryUtils.getSelectedViewId(), + "addons://list/theme", + "The theme category is selected" + ); + + let shortcutsLink = win.document.querySelector( + '#page-options [action="manage-shortcuts"]' + ); + ok(!shortcutsLink.hidden, "The shortcuts link is visible"); + + let loaded = waitForViewLoad(win); + shortcutsLink.click(); + await loaded; + + is( + categoryUtils.getSelectedViewId(), + "addons://list/extension", + "The extension category is now selected" + ); + + return win; +} + +add_task(async function testUpdatingCommands() { + let commands = { + commandZero: {}, + commandOne: { + suggested_key: { default: "Shift+Alt+7" }, + }, + commandTwo: { + description: "Command Two!", + suggested_key: { default: "Alt+4" }, + }, + _execute_browser_action: { + suggested_key: { default: "Shift+Alt+9" }, + }, + }; + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + commands, + browser_action: { default_popup: "popup.html" }, + }, + background() { + browser.commands.onCommand.addListener(commandName => { + browser.test.sendMessage("oncommand", commandName); + }); + browser.test.sendMessage("ready"); + }, + useAddonManager: "temporary", + }); + + await extension.startup(); + await extension.awaitMessage("ready"); + await extensionShortcutsReady(extension.id); + + async function checkShortcut(name, key, modifiers) { + EventUtils.synthesizeKey(key, modifiers); + let message = await extension.awaitMessage("oncommand"); + is( + message, + name, + `Expected onCommand listener to fire with the correct name: ${name}` + ); + } + + // Load the about:addons shortcut view before verify that emitting + // the key events does trigger the expected extension commands. + // There is apparently a race (more likely to be triggered on an + // optimized build) between: + // - the new opened browser window to be ready to listen for the + // keyboard events that are expected to triggered one of the key + // in the extension keyset + // - and the test calling EventUtils.syntesizeKey to test that + // the expected extension command listener is notified. + // + // Loading the shortcut view before calling checkShortcut seems to be + // enough to consistently avoid that race condition. + let win = await loadShortcutsView(); + + // Check that the original shortcuts work. + await checkShortcut("commandOne", "7", { shiftKey: true, altKey: true }); + await checkShortcut("commandTwo", "4", { altKey: true }); + + let doc = win.document; + + let card = doc.querySelector(`.card[addon-id="${extension.id}"]`); + ok(card, `There is a card for the extension`); + + let inputs = card.querySelectorAll(".shortcut-input"); + is( + inputs.length, + Object.keys(commands).length, + "There is an input for each command" + ); + + let nameOrder = Array.from(inputs).map(input => input.getAttribute("name")); + Assert.deepEqual( + nameOrder, + ["commandOne", "commandTwo", "_execute_browser_action", "commandZero"], + "commandZero should be last since it is unset" + ); + + let count = 1; + for (let input of inputs) { + // Change the shortcut. + input.focus(); + EventUtils.synthesizeKey("8", { shiftKey: true, altKey: true }); + count++; + + // Wait for the shortcut attribute to change. + await BrowserTestUtils.waitForCondition( + () => input.getAttribute("shortcut") == "Alt+Shift+8", + "Wait for shortcut to update to Alt+Shift+8" + ); + + // Check that the change worked (but skip if browserAction). + if (input.getAttribute("name") != "_execute_browser_action") { + await checkShortcut(input.getAttribute("name"), "8", { + shiftKey: true, + altKey: true, + }); + } + + // Change it again so it doesn't conflict with the next command. + input.focus(); + EventUtils.synthesizeKey(count.toString(), { + shiftKey: true, + altKey: true, + }); + await BrowserTestUtils.waitForCondition( + () => input.getAttribute("shortcut") == `Alt+Shift+${count}`, + `Wait for shortcut to update to Alt+Shift+${count}` + ); + } + + // Check that errors can be shown. + let input = inputs[0]; + let error = doc.querySelector(".error-message"); + let label = error.querySelector(".error-message-label"); + is(error.style.visibility, "hidden", "The error is initially hidden"); + + // Try a shortcut with only shift for a modifier. + input.focus(); + EventUtils.synthesizeKey("J", { shiftKey: true }); + let possibleErrors = ["shortcuts-modifier-mac", "shortcuts-modifier-other"]; + ok(possibleErrors.includes(label.dataset.l10nId), `The message is set`); + is(error.style.visibility, "visible", "The error is shown"); + + // Escape should clear the focus and hide the error. + is(doc.activeElement, input, "The input is focused"); + EventUtils.synthesizeKey("Escape", {}); + Assert.notEqual(doc.activeElement, input, "The input is no longer focused"); + is(error.style.visibility, "hidden", "The error is hidden"); + + // Check if assigning already assigned shortcut is prevented. + input.focus(); + EventUtils.synthesizeKey("2", { shiftKey: true, altKey: true }); + is(label.dataset.l10nId, "shortcuts-exists", `The message is set`); + is(error.style.visibility, "visible", "The error is shown"); + + // Check the label uses the description first, and has a default for the special cases. + function checkLabel(name, value) { + let input = doc.querySelector(`.shortcut-input[name="${name}"]`); + let label = input.previousElementSibling; + if (label.dataset.l10nId) { + is(label.dataset.l10nId, value, "The l10n-id is set"); + } else { + is(label.textContent, value, "The textContent is set"); + } + } + checkLabel("commandOne", "commandOne"); + checkLabel("commandTwo", "Command Two!"); + checkLabel("_execute_browser_action", "shortcuts-browserAction2"); + + await closeView(win); + await extension.unload(); +}); + +async function startExtensionWithCommands(numCommands) { + let commands = {}; + + for (let i = 0; i < numCommands; i++) { + commands[`command-${i}`] = {}; + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + commands, + }, + background() { + browser.test.sendMessage("ready"); + }, + useAddonManager: "temporary", + }); + + await extension.startup(); + await extension.awaitMessage("ready"); + await extensionShortcutsReady(extension.id); + + return extension; +} + +add_task(async function testExpanding() { + const numCommands = 7; + const visibleCommands = 5; + + let extension = await startExtensionWithCommands(numCommands); + + let win = await loadShortcutsView(); + let doc = win.document; + + let card = doc.querySelector(`.card[addon-id="${extension.id}"]`); + ok(!card.hasAttribute("expanded"), "The card is not expanded"); + + let shortcutRows = card.querySelectorAll(".shortcut-row"); + is(shortcutRows.length, numCommands, `There are ${numCommands} shortcuts`); + + function assertCollapsedVisibility() { + for (let i = 0; i < shortcutRows.length; i++) { + let row = shortcutRows[i]; + if (i < visibleCommands) { + Assert.notEqual( + getComputedStyle(row).display, + "none", + `The first ${visibleCommands} rows are visible` + ); + } else { + is(getComputedStyle(row).display, "none", "The other rows are hidden"); + } + } + } + + // Check the visibility of the rows. + assertCollapsedVisibility(); + + let expandButton = card.querySelector(".expand-button"); + ok(expandButton, "There is an expand button"); + let l10nAttrs = doc.l10n.getAttributes(expandButton); + is(l10nAttrs.id, "shortcuts-card-expand-button", "The expand text is shown"); + is( + l10nAttrs.args.numberToShow, + numCommands - visibleCommands, + "The number to be shown is set on the expand button" + ); + + // Expand the card. + expandButton.click(); + + is(card.getAttribute("expanded"), "true", "The card is now expanded"); + + for (let row of shortcutRows) { + Assert.notEqual( + getComputedStyle(row).display, + "none", + "All the rows are visible" + ); + } + + // The collapse text is now shown. + l10nAttrs = doc.l10n.getAttributes(expandButton); + is( + l10nAttrs.id, + "shortcuts-card-collapse-button", + "The colapse text is shown" + ); + + // Collapse the card. + expandButton.click(); + + ok(!card.hasAttribute("expanded"), "The card is now collapsed again"); + + assertCollapsedVisibility({ collapsed: true }); + + await closeView(win); + await extension.unload(); +}); + +add_task(async function testOneExtraCommandIsNotCollapsed() { + const numCommands = 6; + let extension = await startExtensionWithCommands(numCommands); + + let win = await loadShortcutsView(); + let doc = win.document; + + // The card is not expanded, since it doesn't collapse. + let card = doc.querySelector(`.card[addon-id="${extension.id}"]`); + ok(!card.hasAttribute("expanded"), "The card is not expanded"); + + // Each shortcut has a row. + let shortcutRows = card.querySelectorAll(".shortcut-row"); + is(shortcutRows.length, numCommands, `There are ${numCommands} shortcuts`); + + // There's no expand button, since it can't be expanded. + let expandButton = card.querySelector(".expand-button"); + ok(!expandButton, "There is no expand button"); + + // All of the rows are visible, to avoid a "Show 1 More" button. + for (let row of shortcutRows) { + Assert.notEqual( + getComputedStyle(row).display, + "none", + "All the rows are visible" + ); + } + + await closeView(win); + await extension.unload(); +}); |