Bug 1540108 - Fix Alt+Arrow{Left/Right} key when autocomplete is open. r=Honza.
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Tue, 02 Apr 2019 14:51:37 +0000
changeset 467609 44841e009e9dabdd85079916bf3f74b5fdb5dda6
parent 467608 07800c801230ef8d5d273009496db05e1cff5e37
child 467610 80945e722421a005e54c3c37725c14992b32a23a
push id112638
push userdvarga@mozilla.com
push dateWed, 03 Apr 2019 06:18:49 +0000
treeherdermozilla-inbound@7dd52a4bdab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1540108
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1540108 - Fix Alt+Arrow{Left/Right} key when autocomplete is open. r=Honza. Navigating with Alt + arrow keys on OSX when the autocomplete popup was open wasn't closing the popup, which could lead to weird behavior. The test asserting arrow keys behavior is modified to ensure this works as expected on all the different platforms. Differential Revision: https://phabricator.services.mozilla.com/D25378
devtools/client/webconsole/components/JSTerm.js
devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_arrow_keys.js
--- a/devtools/client/webconsole/components/JSTerm.js
+++ b/devtools/client/webconsole/components/JSTerm.js
@@ -259,20 +259,22 @@ class JSTerm extends Component {
             "Cmd-Up": onArrowUp,
 
             "Down": onArrowDown,
             "Cmd-Down": onArrowDown,
 
             "Left": onArrowLeft,
             "Ctrl-Left": onArrowLeft,
             "Cmd-Left": onArrowLeft,
+            "Alt-Left": onArrowLeft,
 
             "Right": onArrowRight,
             "Ctrl-Right": onArrowRight,
             "Cmd-Right": onArrowRight,
+            "Alt-Right": onArrowRight,
 
             "Ctrl-N": () => {
               // Control-N differs from down arrow: it ignores autocomplete state.
               // Note that we preserve the default 'down' navigation within
               // multiline text.
               if (
                 Services.appinfo.OS === "Darwin"
                 && this.canCaretGoNext()
@@ -903,16 +905,17 @@ class JSTerm extends Component {
       ) {
         this.clearCompletion();
       }
 
       // We only want to complete on Right arrow if the completion text is displayed.
       if (event.keyCode === KeyCodes.DOM_VK_RIGHT) {
         if (this.getAutoCompletionText()) {
           this.acceptProposedCompletion();
+          event.preventDefault();
         }
         this.clearCompletion();
         event.preventDefault();
       }
 
       return;
     } else if (event.keyCode == KeyCodes.DOM_VK_RETURN) {
       if (!this.autocompletePopup.isOpen && (
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_arrow_keys.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_arrow_keys.js
@@ -6,17 +6,18 @@
 "use strict";
 
 const TEST_URI = `data:text/html;charset=utf-8,<head><script>
     /* Create a prototype-less object so popup does not contain native
      * Object prototype properties.
      */
     window.foo = Object.create(null, Object.getOwnPropertyDescriptors({
       aa: "a",
-      bb: "b",
+      bbb: "b",
+      bbbb: "b",
     }));
   </script></head><body>Autocomplete text navigation key usage test</body>`;
 
 add_task(async function() {
   // Run test with legacy JsTerm
   await pushPref("devtools.webconsole.jsterm.codeMirror", false);
   await performTests();
   // And then run it with the CodeMirror-powered one.
@@ -24,75 +25,157 @@ add_task(async function() {
   await performTests();
 });
 
 async function performTests() {
   const hud = await openNewTabAndConsole(TEST_URI);
   const { jsterm } = hud;
   const { autocompletePopup: popup } = jsterm;
 
-  const checkInput = (expected, assertionInfo) =>
-    checkInputValueAndCursorPosition(hud, expected, assertionInfo);
-
-  let onPopUpOpen = popup.once("popup-opened");
-  setInputValue(hud, "window.foo");
-  EventUtils.sendString(".");
-  await onPopUpOpen;
-
-  info("Trigger autocomplete popup opening");
-  // checkInput is asserting the cursor position with the "|" char.
-  checkInput("window.foo.|");
-  is(popup.isOpen, true, "popup is open");
-  checkInputCompletionValue(hud, "           aa", "completeNode has expected value");
-
-  info("Test that arrow left closes the popup and clears complete node");
-  let onPopUpClose = popup.once("popup-closed");
-  EventUtils.synthesizeKey("KEY_ArrowLeft");
-  await onPopUpClose;
-  checkInput("window.foo|.");
-  is(popup.isOpen, false, "popup is closed");
-  checkInputCompletionValue(hud, "", "completeNode is empty");
-
-  info("Trigger autocomplete popup opening again");
-  onPopUpOpen = popup.once("popup-opened");
-  setInputValue(hud, "window.foo");
-  EventUtils.sendString(".");
-  await onPopUpOpen;
-
-  checkInput("window.foo.|");
-  is(popup.isOpen, true, "popup is open");
-  checkInputCompletionValue(hud, "           aa", "completeNode has expected value");
-
-  info("Test that arrow right selects selected autocomplete item");
-  onPopUpClose = popup.once("popup-closed");
-  EventUtils.synthesizeKey("KEY_ArrowRight");
-  await onPopUpClose;
-  checkInput("window.foo.aa|");
-  is(popup.isOpen, false, "popup is closed");
-  checkInputCompletionValue(hud, "", "completeNode is empty");
-
-  info("Test that Ctrl/Cmd + Left removes complete node");
-  await setInputValueForAutocompletion(hud, "window.foo.a");
-  const prefix = getInputValue(hud).replace(/[\S]/g, " ");
-  checkInputCompletionValue(hud, prefix + "a", "completeNode has expected value");
-
-  const isOSX = Services.appinfo.OS == "Darwin";
-  EventUtils.synthesizeKey("KEY_ArrowLeft", {
-    [isOSX ? "metaKey" : "ctrlKey"]: true,
-  });
-  checkInputCompletionValue(hud, "",
-    "completeNode was cleared after Ctrl/Cmd + left");
+  await checkArrowLeftDismissPopup(hud);
+  await checkArrowLeftDismissCompletion(hud);
+  await checkArrowRightAcceptCompletion(hud);
 
   info("Test that Ctrl/Cmd + Right closes the popup if there's text after cursor");
   setInputValue(hud, ".");
   EventUtils.synthesizeKey("KEY_ArrowLeft");
-  onPopUpOpen = popup.once("popup-opened");
+  const onPopUpOpen = popup.once("popup-opened");
   EventUtils.sendString("win");
   await onPopUpOpen;
   ok(popup.isOpen, "popup is open");
 
-  onPopUpClose = popup.once("popup-closed");
+  const isOSX = Services.appinfo.OS == "Darwin";
+  const onPopUpClose = popup.once("popup-closed");
   EventUtils.synthesizeKey("KEY_ArrowRight", {
     [isOSX ? "metaKey" : "ctrlKey"]: true,
   });
   await onPopUpClose;
   is(getInputValue(hud), "win.", "input value wasn't modified");
 }
+
+async function checkArrowLeftDismissPopup(hud) {
+  const popup = hud.jsterm.autocompletePopup;
+  let tests;
+  if (Services.appinfo.OS == "Darwin") {
+    tests = [{
+      keyOption: null,
+      expectedInput: "window.foo.b|b",
+    }, {
+      keyOption: {metaKey: true},
+      expectedInput: "|window.foo.bb",
+    }, {
+      keyOption: {altKey: true},
+      expectedInput: "window.foo.|bb",
+    }];
+  } else {
+    tests = [{
+      keyOption: null,
+      expectedInput: "window.foo.b|b",
+    }, {
+      keyOption: {ctrlKey: true},
+      expectedInput: "window.foo.|bb",
+    }];
+  }
+
+  for (const test of tests) {
+    info("Trigger autocomplete popup opening");
+    const onPopUpOpen = popup.once("popup-opened");
+    await setInputValueForAutocompletion(hud, "window.foo.bb");
+    await onPopUpOpen;
+
+    // checkInput is asserting the cursor position with the "|" char.
+    checkInputValueAndCursorPosition(hud, "window.foo.bb|");
+    is(popup.isOpen, true, "popup is open");
+    checkInputCompletionValue(hud, "             b", "completeNode has expected value");
+
+    const {keyOption, expectedInput} = test;
+    info(`Test that arrow left closes the popup and clears complete node`);
+    const onPopUpClose = popup.once("popup-closed");
+    EventUtils.synthesizeKey("KEY_ArrowLeft", keyOption);
+    await onPopUpClose;
+
+    checkInputValueAndCursorPosition(hud, expectedInput);
+    is(popup.isOpen, false, "popup is closed");
+    checkInputCompletionValue(hud, "", "completeNode is empty");
+  }
+  setInputValue(hud, "");
+}
+
+async function checkArrowLeftDismissCompletion(hud) {
+  let tests;
+  if (Services.appinfo.OS == "Darwin") {
+    tests = [{
+      keyOption: null,
+      expectedInput: "window.foo.|a",
+    }, {
+      keyOption: {metaKey: true},
+      expectedInput: "|window.foo.a",
+    }, {
+      keyOption: {altKey: true},
+      expectedInput: "window.foo.|a",
+    }];
+  } else {
+    tests = [{
+      keyOption: null,
+      expectedInput: "window.foo.|a",
+    }, {
+      keyOption: {ctrlKey: true},
+      expectedInput: "window.foo.|a",
+    }];
+  }
+
+  for (const test of tests) {
+    await setInputValueForAutocompletion(hud, "window.foo.a");
+    const prefix = getInputValue(hud).replace(/[\S]/g, " ");
+    checkInputCompletionValue(hud, prefix + "a", "completeNode has expected value");
+
+    info(`Test that arrow left dismiss the completion text`);
+    const {keyOption, expectedInput} = test;
+    EventUtils.synthesizeKey("KEY_ArrowLeft", keyOption);
+
+    checkInputValueAndCursorPosition(hud, expectedInput);
+    checkInputCompletionValue(hud, "", "completeNode is empty");
+  }
+  setInputValue(hud, "");
+}
+
+async function checkArrowRightAcceptCompletion(hud) {
+  const popup = hud.jsterm.autocompletePopup;
+  let tests;
+  if (Services.appinfo.OS == "Darwin") {
+    tests = [{
+      keyOption: null,
+    }, {
+      keyOption: {metaKey: true},
+    }, {
+      keyOption: {altKey: true},
+    }];
+  } else {
+    tests = [{
+      keyOption: null,
+    }, {
+      keyOption: {ctrlKey: true},
+    }];
+  }
+
+  for (const test of tests) {
+    info("Trigger autocomplete popup opening");
+    const onPopUpOpen = popup.once("popup-opened");
+    await setInputValueForAutocompletion(hud, `window.foo.bb`);
+    await onPopUpOpen;
+
+    // checkInput is asserting the cursor position with the "|" char.
+    checkInputValueAndCursorPosition(hud, `window.foo.bb|`);
+    is(popup.isOpen, true, "popup is open");
+    checkInputCompletionValue(hud, "             b", "completeNode has expected value");
+
+    const {keyOption} = test;
+    info(`Test that arrow right closes the popup and accepts the completion`);
+    const onPopUpClose = popup.once("popup-closed");
+    EventUtils.synthesizeKey("KEY_ArrowRight", keyOption);
+    await onPopUpClose;
+
+    checkInputValueAndCursorPosition(hud, "window.foo.bbb|");
+    is(popup.isOpen, false, "popup is closed");
+    checkInputCompletionValue(hud, "", "completeNode is empty");
+  }
+  setInputValue(hud, "");
+}