Bug 1565273 - Context menu clicks ignore browser.urlbar.clickSelectsAll pref. Add tests for selectAll behaviour. r=mak a=pascalc
authorharry <htwyford@mozilla.com>
Wed, 07 Aug 2019 22:49:15 +0200
changeset 544985 d09aa77d6ee4cc96ead672b5f1da4d14d5f63223
parent 544984 31cd2ca2e2d9104636a3ca070ac82bc6edddbd79
child 544986 60b277d0ef161532e1b25601d23f1d3bbca47e98
push id2131
push userffxbld-merge
push dateMon, 26 Aug 2019 18:30:20 +0000
treeherdermozilla-release@b19ffb3ca153 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak, pascalc
bugs1565273
milestone69.0
Bug 1565273 - Context menu clicks ignore browser.urlbar.clickSelectsAll pref. Add tests for selectAll behaviour. r=mak a=pascalc
browser/components/urlbar/UrlbarInput.jsm
browser/components/urlbar/tests/browser/browser.ini
browser/components/urlbar/tests/browser/browser_urlbar_selection.js
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -1430,21 +1430,23 @@ class UrlbarInput {
    */
   _notifyStartNavigation(result) {
     Services.obs.notifyObservers({ result }, "urlbar-user-start-navigation");
   }
 
   /**
    * Determines if we should select all the text in the Urlbar based on the
    * clickSelectsAll pref, Urlbar state, and whether the selection is empty.
+   * @param {boolean} [ignoreClickSelectsAllPref]
+   *        If true, the browser.urlbar.clickSelectsAll pref will be ignored.
    */
-  _maybeSelectAll() {
+  _maybeSelectAll(ignoreClickSelectsAllPref = false) {
     if (
       !this._preventClickSelectsAll &&
-      UrlbarPrefs.get("clickSelectsAll") &&
+      (ignoreClickSelectsAllPref || UrlbarPrefs.get("clickSelectsAll")) &&
       this._compositionState != UrlbarUtils.COMPOSITION.COMPOSING &&
       this.document.activeElement == this.inputField &&
       this.inputField.selectionStart == this.inputField.selectionEnd
     ) {
       this.editor.selectAll();
     }
   }
 
@@ -1491,29 +1493,24 @@ class UrlbarInput {
     this._resetSearchState();
   }
 
   _on_click(event) {
     this._maybeSelectAll();
   }
 
   _on_contextmenu(event) {
-    // On Windows, the context menu appears on mouseup. macOS and Linux require
-    // special handling to selectAll when the contextmenu is displayed.
-    // See bug 576135 comment 4 for details.
-    if (AppConstants.platform == "win") {
-      return;
-    }
-
     // Context menu opened via keyboard shortcut.
     if (!event.button) {
       return;
     }
 
-    this._maybeSelectAll();
+    // If the user right clicks, we select all regardless of the value of
+    // the browser.urlbar.clickSelectsAll pref.
+    this._maybeSelectAll(/* ignoreClickSelectsAllPref */ event.button == 2);
   }
 
   _on_focus(event) {
     this._updateUrlTooltip();
     this.formatValue();
 
     // Hide popup notifications, to reduce visual noise.
     if (this.getAttribute("pageproxystate") != "valid") {
--- a/browser/components/urlbar/tests/browser/browser.ini
+++ b/browser/components/urlbar/tests/browser/browser.ini
@@ -116,16 +116,18 @@ support-files =
   searchSuggestionEngine.sjs
 [browser_urlbar_locationchange_urlbar_edit_dos.js]
 support-files =
   file_urlbar_edit_dos.html
 [browser_urlbar_remoteness_switch.js]
 run-if = e10s
 [browser_urlbar_remove_match.js]
 [browser_urlbar_searchsettings.js]
+[browser_urlbar_selection.js]
+skip-if = (os == 'mac') # bug 1570474
 [browser_urlbar_speculative_connect.js]
 support-files =
   searchSuggestionEngine2.xml
   searchSuggestionEngine.sjs
 [browser_urlbar_speculative_connect_not_with_client_cert.js]
 [browser_urlbar_whereToOpen.js]
 [browser_urlbarAboutHomeLoading.js]
 [browser_urlbarCopying.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/tests/browser/browser_urlbar_selection.js
@@ -0,0 +1,235 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const exampleSearch = "f oo  bar";
+const exampleUrl = "https://example.com/1";
+
+const { UrlbarTestUtils } = ChromeUtils.import(
+  "resource://testing-common/UrlbarTestUtils.jsm"
+);
+
+function click(target) {
+  let promise = BrowserTestUtils.waitForEvent(target, "click");
+  EventUtils.synthesizeMouseAtCenter(target, {}, target.ownerGlobal);
+  return promise;
+}
+
+function openContextMenu(target) {
+  let popupShownPromise = BrowserTestUtils.waitForEvent(
+    target.ownerGlobal,
+    "contextmenu"
+  );
+
+  EventUtils.synthesizeMouseAtCenter(
+    target,
+    {
+      type: "contextmenu",
+      button: 2,
+    },
+    target.ownerGlobal
+  );
+  return popupShownPromise;
+}
+
+function drag(target, fromX, fromY, toX, toY) {
+  let promise = BrowserTestUtils.waitForEvent(target, "mouseup");
+  EventUtils.synthesizeMouse(
+    target,
+    fromX,
+    fromY,
+    { type: "mousemove" },
+    target.ownerGlobal
+  );
+  EventUtils.synthesizeMouse(
+    target,
+    fromX,
+    fromY,
+    { type: "mousedown" },
+    target.ownerGlobal
+  );
+  EventUtils.synthesizeMouse(
+    target,
+    toX,
+    toY,
+    { type: "mousemove" },
+    target.ownerGlobal
+  );
+  EventUtils.synthesizeMouse(
+    target,
+    toX,
+    toY,
+    { type: "mouseup" },
+    target.ownerGlobal
+  );
+  return promise;
+}
+
+add_task(async function setup() {
+  SpecialPowers.pushPrefEnv({
+    set: [["browser.urlbar.clickSelectsAll", true]],
+  });
+
+  // On macOS, we must "warm up" the Urlbar to get the first test to pass.
+  gURLBar.value = "";
+  await click(gURLBar.inputField);
+  gURLBar.blur();
+});
+
+add_task(async function leftClickSelectsAll() {
+  gURLBar.value = exampleSearch;
+  await click(gURLBar.inputField);
+  Assert.equal(
+    gURLBar.selectionStart,
+    0,
+    "The entire search term should be selected."
+  );
+  Assert.equal(
+    gURLBar.selectionEnd,
+    exampleSearch.length,
+    "The entire search term should be selected."
+  );
+  gURLBar.blur();
+});
+
+add_task(async function leftClickSelectsUrl() {
+  gURLBar.value = exampleUrl;
+  await click(gURLBar.inputField);
+  Assert.equal(gURLBar.selectionStart, 0, "The entire url should be selected.");
+  Assert.equal(
+    gURLBar.selectionEnd,
+    exampleUrl.length,
+    "The entire url should be selected."
+  );
+  gURLBar.blur();
+});
+
+// Test to ensure that the doubleClickSelectsAll pref does not interfere with
+// single click behaviour (Double CSA itself is tested in
+// urlbar/tests/browser_doubleClickSelectsAll.js).
+add_task(async function bothPrefsEnabled() {
+  Services.prefs.setBoolPref("browser.urlbar.doubleClickSelectsAll", true);
+  gURLBar.value = exampleSearch;
+  await click(gURLBar.inputField);
+  Assert.equal(
+    gURLBar.selectionStart,
+    0,
+    "The entire search term should be selected."
+  );
+  Assert.equal(
+    gURLBar.selectionEnd,
+    exampleSearch.length,
+    "The entire search term should be selected."
+  );
+  gURLBar.blur();
+  Services.prefs.clearUserPref("browser.urlbar.doubleClickSelectsAll");
+});
+
+add_task(async function rightClickSelectsAll() {
+  // The text should be selected even when the pref is disabled.
+  await SpecialPowers.pushPrefEnv({
+    set: [["browser.urlbar.clickSelectsAll", false]],
+  });
+
+  gURLBar.inputField.focus();
+  gURLBar.value = exampleUrl;
+
+  // Remove the selection so the focus() call above doesn't influence the test.
+  gURLBar.selectionStart = gURLBar.selectionEnd = 0;
+
+  await openContextMenu(gURLBar.inputField);
+
+  Assert.equal(gURLBar.selectionStart, 0, "The entire URL should be selected.");
+  Assert.equal(
+    gURLBar.selectionEnd,
+    exampleUrl.length,
+    "The entire URL should be selected."
+  );
+
+  let textBox = document.getAnonymousElementByAttribute(
+    gURLBar.textbox,
+    "anonid",
+    "moz-input-box"
+  );
+  let contextMenu = textBox.menupopup;
+
+  // While the context menu is open, test the "Select All" button.
+  let contextMenuItem = contextMenu.firstElementChild;
+  while (
+    contextMenuItem.nextElementSibling &&
+    contextMenuItem.getAttribute("cmd") != "cmd_selectAll"
+  ) {
+    contextMenuItem = contextMenuItem.nextElementSibling;
+  }
+  Assert.ok(
+    contextMenuItem,
+    "The context menu should have the select all menu item."
+  );
+
+  let controller = document.commandDispatcher.getControllerForCommand(
+    contextMenuItem.getAttribute("cmd")
+  );
+  let enabled = controller.isCommandEnabled(
+    contextMenuItem.getAttribute("cmd")
+  );
+  Assert.ok(enabled, "The context menu select all item should be enabled.");
+
+  await click(contextMenuItem);
+  Assert.equal(
+    gURLBar.selectionStart,
+    0,
+    "The entire URL should be selected after clicking selectAll button."
+  );
+  Assert.equal(
+    gURLBar.selectionEnd,
+    exampleUrl.length,
+    "The entire URL should be selected after clicking selectAll button."
+  );
+
+  contextMenu.hidePopup();
+  gURLBar.blur();
+  await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function contextMenuDoesNotCancelSelection() {
+  gURLBar.inputField.focus();
+  gURLBar.value = exampleUrl;
+
+  gURLBar.selectionStart = 3;
+  gURLBar.selectionEnd = 7;
+
+  await openContextMenu(gURLBar.inputField);
+
+  Assert.equal(
+    gURLBar.selectionStart,
+    3,
+    "The selection should not have changed."
+  );
+  Assert.equal(
+    gURLBar.selectionEnd,
+    7,
+    "The selection should not have changed."
+  );
+
+  let textBox = document.getAnonymousElementByAttribute(
+    gURLBar.textbox,
+    "anonid",
+    "moz-input-box"
+  );
+  textBox.menupopup.hidePopup();
+
+  gURLBar.blur();
+});
+
+add_task(async function dragSelect() {
+  gURLBar.value = exampleSearch.repeat(10);
+  // Drags from an artibrary offset of 30 to test for bug 1562145: that the
+  // selection does not start at the beginning.
+  await drag(gURLBar.inputField, 30, 0, 60, 0);
+  Assert.greater(
+    gURLBar.selectionStart,
+    0,
+    "Selection should not start at the beginning of the string."
+  );
+});