Bug 1384185 - [Form Autofill] Fallback to form-history when available values from saved profiles are less than 3. r=steveck
authorLuke Chang <lchang@mozilla.com>
Mon, 31 Jul 2017 17:42:08 +0800
changeset 423758 99d5923bcdbb748cb301519dbf80be5c1726ce9b
parent 423757 63ddd74e45786ff2aa6dd84581463932afe75cf7
child 423759 303b2be541c6c4411da0e5dfaac9a645944d0afd
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssteveck
bugs1384185
milestone56.0
Bug 1384185 - [Form Autofill] Fallback to form-history when available values from saved profiles are less than 3. r=steveck MozReview-Commit-ID: H2EB23IZ9D5
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/test/mochitest/formautofill_common.js
browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -85,49 +85,57 @@ AutofillProfileAutoCompleteSearch.protot
    *
    * @param {string} searchString the string to search for
    * @param {string} searchParam
    * @param {Object} previousResult a previous result to use for faster searchinig
    * @param {Object} listener the listener to notify when the search is complete
    */
   startSearch(searchString, searchParam, previousResult, listener) {
     this.log.debug("startSearch: for", searchString, "with input", formFillController.focusedInput);
+
+    this.forceStop = false;
+
+    let savedFieldNames = FormAutofillContent.savedFieldNames;
+
     let focusedInput = formFillController.focusedInput;
-    this.forceStop = false;
     let info = FormAutofillContent.getInputDetails(focusedInput);
+    let isAddressField = FormAutofillUtils.isAddressField(info.fieldName);
+    let handler = FormAutofillContent.getFormHandler(focusedInput);
+    let allFieldNames = handler.allFieldNames;
+    let filledRecordGUID = isAddressField ? handler.address.filledRecordGUID : handler.creditCards.filledRecordGUID;
 
-    if (!FormAutofillContent.savedFieldNames.has(info.fieldName) ||
-        FormAutofillContent.getFormHandler(focusedInput).address.filledRecordGUID) {
+    // Fallback to form-history if ...
+    //   - no profile can fill the currently-focused input.
+    //   - the current form has already been populated.
+    //   - (address only) less than 3 inputs are covered by all saved fields in the storage.
+    if (!savedFieldNames.has(info.fieldName) || filledRecordGUID || (isAddressField &&
+        allFieldNames.filter(field => savedFieldNames.has(field)).length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD)) {
       let formHistory = Cc["@mozilla.org/autocomplete/search;1?name=form-history"]
                           .createInstance(Ci.nsIAutoCompleteSearch);
       formHistory.startSearch(searchString, searchParam, previousResult, {
         onSearchResult: (search, result) => {
           listener.onSearchResult(this, result);
           ProfileAutocomplete.setProfileAutoCompleteResult(result);
         },
       });
       return;
     }
 
-    let collectionName = FormAutofillUtils.isAddressField(info.fieldName) ?
-      "addresses" : "creditCards";
+    let collectionName = isAddressField ? "addresses" : "creditCards";
 
     this._getRecords({collectionName, info, searchString}).then((records) => {
       if (this.forceStop) {
         return;
       }
       // Sort addresses by timeLastUsed for showing the lastest used address at top.
       records.sort((a, b) => b.timeLastUsed - a.timeLastUsed);
 
-      let handler = FormAutofillContent.getFormHandler(focusedInput);
       let adaptedRecords = handler.getAdaptedProfiles(records);
-
-      let allFieldNames = FormAutofillContent.getAllFieldNames(focusedInput);
       let result = null;
-      if (collectionName == "addresses") {
+      if (isAddressField) {
         result = new AddressResult(searchString,
                                    info.fieldName,
                                    allFieldNames,
                                    adaptedRecords,
                                    {});
       } else {
         result = new CreditCardResult(searchString,
                                       info.fieldName,
--- a/browser/extensions/formautofill/test/mochitest/formautofill_common.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_common.js
@@ -56,17 +56,18 @@ function checkMenuEntries(expectedValues
 }
 
 async function addAddress(address) {
   return new Promise(resolve => {
     formFillChromeScript.sendAsyncMessage("FormAutofillTest:AddAddress", {address});
     formFillChromeScript.addMessageListener("FormAutofillTest:AddressAdded", function onAdded(data) {
       formFillChromeScript.removeMessageListener("FormAutofillTest:AddressAdded", onAdded);
 
-      resolve();
+      SimpleTest.requestFlakyTimeout("Ensure ProfileAutocomplete is registered");
+      setTimeout(resolve, 500);
     });
   });
 }
 
 async function removeAddress(guid) {
   return new Promise(resolve => {
     formFillChromeScript.sendAsyncMessage("FormAutofillTest:RemoveAddress", {guid});
     formFillChromeScript.addMessageListener("FormAutofillTest:AddressRemoved", function onDeleted(data) {
@@ -94,16 +95,27 @@ async function checkAddresses(expectedAd
     formFillChromeScript.addMessageListener("FormAutofillTest:areAddressesMatching", function onChecked(data) {
       formFillChromeScript.removeMessageListener("FormAutofillTest:areAddressesMatching", onChecked);
 
       resolve(data);
     });
   });
 }
 
+async function cleanUpAddress() {
+  return new Promise(resolve => {
+    formFillChromeScript.sendAsyncMessage("FormAutofillTest:CleanUpAddress", {});
+    formFillChromeScript.addMessageListener("FormAutofillTest:AddressCleanedUp", function onCleanedUp(data) {
+      formFillChromeScript.removeMessageListener("FormAutofillTest:AddressCleanedUp", onCleanedUp);
+
+      resolve(data);
+    });
+  });
+}
+
 // Utils for registerPopupShownListener(in satchel_common.js) that handles dropdown popup
 // Please call "initPopupListener()" in your test and "await expectPopup()"
 // if you want to wait for dropdown menu displayed.
 function expectPopup() {
   info("expecting a popup");
   return new Promise(resolve => {
     expectingPopup = resolve;
   });
--- a/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
@@ -12,16 +12,24 @@ let {profileStorage} = Cu.import("resour
 var ParentUtils = {
   cleanUpAddress() {
     Services.cpmm.addMessageListener("FormAutofill:Records", function getResult(result) {
       Services.cpmm.removeMessageListener("FormAutofill:Records", getResult);
 
       let addresses = result.data;
       Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses",
                                      {guids: addresses.map(address => address.guid)});
+
+      let count = addresses.length;
+      Services.obs.addObserver(function observer(subject, topic, data) {
+        if (!--count) {
+          Services.obs.removeObserver(observer, topic);
+          sendAsyncMessage("FormAutofillTest:AddressCleanedUp");
+        }
+      }, "formautofill-storage-changed");
     });
 
     Services.cpmm.sendAsyncMessage("FormAutofill:GetRecords", {searchString: "", collectionName: "addresses"});
   },
 
   updateAddress(type, chromeMsg, msgData, contentMsg) {
     Services.cpmm.sendAsyncMessage(chromeMsg, msgData);
     Services.obs.addObserver(function observer(subject, topic, data) {
@@ -99,11 +107,15 @@ addMessageListener("FormAutofillTest:Rem
 addMessageListener("FormAutofillTest:UpdateAddress", (msg) => {
   ParentUtils.updateAddress("update", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressUpdated");
 });
 
 addMessageListener("FormAutofillTest:CheckAddresses", (msg) => {
   ParentUtils.checkAddresses(msg);
 });
 
+addMessageListener("FormAutofillTest:CleanUpAddress", (msg) => {
+  ParentUtils.cleanUpAddress();
+});
+
 addMessageListener("cleanup", () => {
   ParentUtils.cleanup();
 });
--- a/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
+++ b/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
@@ -99,16 +99,31 @@ add_task(async function history_only_men
   await setupFormHistory();
 
   await setInput("#tel", "");
   doKey("down");
   await expectPopup();
   checkMenuEntries(["+1234567890"], false);
 });
 
+// Display history search result if less than 3 inputs are covered by all saved
+// fields in the storage.
+add_task(async function all_saved_fields_less_than_threshold() {
+  await addAddress({
+    email: "test@test.com",
+  });
+
+  await setInput("#email", "");
+  doKey("down");
+  await expectPopup();
+  checkMenuEntries(["foo@mozilla.com"], false);
+
+  await cleanUpAddress();
+});
+
 // Form with both history and address storage.
 add_task(async function check_menu_when_both_existed() {
   await setupAddressStorage();
 
   await setInput("#organization", "");
   doKey("down");
   await expectPopup();
   checkMenuEntries(MOCK_STORAGE.map(address =>