Bug 1328778 - Implement ProfileAutoCompleteResult for Profile AutoFormFill usage only.; r=MattN
authorSean Lee <selee@mozilla.com>
Fri, 30 Dec 2016 12:06:06 +0800
changeset 328603 ff26bfb05b6cbf05f35e7430ddf1052fd2f9fb4a
parent 328602 daeecaee4447252f5e1259b523061353671b98b4
child 328604 ddbb54e48d54c62350c1f58ca2138664e2efc8e1
push id85493
push userkwierso@gmail.com
push dateTue, 10 Jan 2017 00:45:12 +0000
treeherdermozilla-inbound@7822749b1b14 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1328778
milestone53.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 1328778 - Implement ProfileAutoCompleteResult for Profile AutoFormFill usage only.; r=MattN MozReview-Commit-ID: 63LHFgC66X8
browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
browser/extensions/formautofill/content/FormAutofillContent.js
browser/extensions/formautofill/test/unit/test_profileAutocompleteResult.js
browser/extensions/formautofill/test/unit/xpcshell.ini
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -0,0 +1,129 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["ProfileAutoCompleteResult"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+this.ProfileAutoCompleteResult = function(searchString,
+                                           fieldName,
+                                           matchingProfiles,
+                                           {resultCode = null}) {
+  this.searchString = searchString;
+  this._fieldName = fieldName;
+  this._matchingProfiles = matchingProfiles;
+
+  if (resultCode) {
+    this.searchResult = resultCode;
+  } else if (matchingProfiles.length > 0) {
+    this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
+  } else {
+    this.searchResult = Ci.nsIAutoCompleteResult.RESULT_NOMATCH;
+  }
+};
+
+ProfileAutoCompleteResult.prototype = {
+
+  // The user's query string
+  searchString: "",
+
+  // The default item that should be entered if none is selected
+  defaultIndex: 0,
+
+  // The reason the search failed
+  errorDescription: "",
+
+  // The result code of this result object.
+  searchResult: null,
+
+  // The autocomplete attribute of the focused input field
+  _fieldName: "",
+
+  // The matching profiles contains the information for filling forms.
+  _matchingProfiles: null,
+
+  /**
+   * @returns {number} The number of results
+   */
+  get matchCount() {
+    return this._matchingProfiles.length;
+  },
+
+  _checkIndexBounds(index) {
+    if (index < 0 || index >= this._matchingProfiles.length) {
+      throw Components.Exception("Index out of range.", Cr.NS_ERROR_ILLEGAL_VALUE);
+    }
+  },
+
+  /**
+   * Retrieves a result
+   * @param   {number} index The index of the result requested
+   * @returns {string} The result at the specified index
+   */
+  getValueAt(index) {
+    this._checkIndexBounds(index);
+    return this._matchingProfiles[index].guid;
+  },
+
+  getLabelAt(index) {
+    this._checkIndexBounds(index);
+    return this._matchingProfiles[index].organization;
+  },
+
+  /**
+   * Retrieves a comment (metadata instance)
+   * @param   {number} index The index of the comment requested
+   * @returns {string} The comment at the specified index
+   */
+  getCommentAt(index) {
+    this._checkIndexBounds(index);
+    return this._matchingProfiles[index].streetAddress;
+  },
+
+  /**
+   * Retrieves a style hint specific to a particular index.
+   * @param   {number} index The index of the style hint requested
+   * @returns {string} The style hint at the specified index
+   */
+  getStyleAt(index) {
+    this._checkIndexBounds(index);
+    return "autofill-profile";
+  },
+
+  /**
+   * Retrieves an image url.
+   * @param   {number} index The index of the image url requested
+   * @returns {string} The image url at the specified index
+   */
+  getImageAt(index) {
+    this._checkIndexBounds(index);
+    return "";
+  },
+
+  /**
+   * Retrieves a result
+   * @param   {number} index The index of the result requested
+   * @returns {string} The result at the specified index
+   */
+  getFinalCompleteValueAt(index) {
+    return this.getValueAt(index);
+  },
+
+  /**
+   * Removes a result from the resultset
+   * @param {number} index The index of the result to remove
+   * @param {boolean} removeFromDatabase TRUE for removing data from DataBase
+   *                                     as well.
+   */
+  removeValueAt(index, removeFromDatabase) {
+    // There is no plan to support removing profiles via autocomplete.
+  },
+
+  // nsISupports
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult]),
+};
--- a/browser/extensions/formautofill/content/FormAutofillContent.js
+++ b/browser/extensions/formautofill/content/FormAutofillContent.js
@@ -6,18 +6,19 @@
  * Form Autofill frame script.
  */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr, manager: Cm} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/nsFormAutoCompleteResult.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ProfileAutoCompleteResult",
+                                  "resource://formautofill/ProfileAutoCompleteResult.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FormLikeFactory",
                                   "resource://gre/modules/FormLikeFactory.jsm");
 
 const formFillController = Cc["@mozilla.org/satchel/form-fill-controller;1"]
                              .getService(Ci.nsIFormFillController);
 
 const AUTOFILL_FIELDS_THRESHOLD = 3;
 
@@ -222,23 +223,29 @@ 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) {
     // TODO: These mock data should be replaced by form autofill API
-    let labels = ["Mary", "John"];
-    let values = ["Mary S.", "John S."];
-    let comments = ["123 Sesame Street.", "331 E. Evelyn Avenue"];
-    let result = new FormAutoCompleteResult(searchString,
-                                            Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
-                                            0, "", values, labels,
-                                            comments);
+    let fieldName = "name";
+    let profiles = [{
+      guid: "test-guid-1",
+      organization: "Sesame Street",
+      streetAddress: "123 Sesame Street.",
+      tel: "1-345-345-3456.",
+    }, {
+      guid: "test-guid-2",
+      organization: "Mozilla",
+      streetAddress: "331 E. Evelyn Avenue",
+      tel: "1-650-903-0800",
+    }];
+    let result = new ProfileAutoCompleteResult(searchString, fieldName, profiles, {});
 
     listener.onSearchResult(this, result);
   },
 
   /**
    * Stops an asynchronous search that is in progress
    */
   stopSearch() {
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/test_profileAutocompleteResult.js
@@ -0,0 +1,82 @@
+"use strict";
+
+Cu.import("resource://formautofill/ProfileAutoCompleteResult.jsm");
+
+let matchingProfiles = [{
+  guid: "test-guid-1",
+  organization: "Sesame Street",
+  streetAddress: "123 Sesame Street.",
+  tel: "1-345-345-3456.",
+}, {
+  guid: "test-guid-2",
+  organization: "Mozilla",
+  streetAddress: "331 E. Evelyn Avenue",
+  tel: "1-650-903-0800",
+}];
+
+let testCases = [{
+  options: {},
+  matchingProfiles: matchingProfiles,
+  searchString: "",
+  fieldName: "",
+  expected: {
+    searchResult: Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
+    defaultIndex: 0,
+    items: [{
+      style: "autofill-profile",
+      image: "",
+    }, {
+      style: "autofill-profile",
+      image: "",
+    }],
+  },
+}, {
+  options: {},
+  matchingProfiles: [],
+  searchString: "",
+  fieldName: "",
+  expected: {
+    searchResult: Ci.nsIAutoCompleteResult.RESULT_NOMATCH,
+    defaultIndex: 0,
+    items: [],
+  },
+}, {
+  options: {resultCode: Ci.nsIAutoCompleteResult.RESULT_FAILURE},
+  matchingProfiles: [],
+  searchString: "",
+  fieldName: "",
+  expected: {
+    searchResult: Ci.nsIAutoCompleteResult.RESULT_FAILURE,
+    defaultIndex: 0,
+    items: [],
+  },
+}];
+
+add_task(function* test_all_patterns() {
+  testCases.forEach(pattern => {
+    let actual = new ProfileAutoCompleteResult(pattern.searchString,
+                                               pattern.fieldName,
+                                               pattern.matchingProfiles,
+                                               pattern.options);
+    let expectedValue = pattern.expected;
+    equal(actual.searchResult, expectedValue.searchResult);
+    equal(actual.defaultIndex, expectedValue.defaultIndex);
+    equal(actual.matchCount, expectedValue.items.length);
+    expectedValue.items.forEach((item, index) => {
+      // TODO: getValueAt, getLabelAt, and getCommentAt should be verified here.
+      equal(actual.getStyleAt(index), item.style);
+      equal(actual.getImageAt(index), item.image);
+    });
+
+    if (expectedValue.items.length != 0) {
+      Assert.throws(() => actual.getValueAt(expectedValue.items.length),
+        /Index out of range\./);
+
+      Assert.throws(() => actual.getLabelAt(expectedValue.items.length),
+        /Index out of range\./);
+
+      Assert.throws(() => actual.getCommentAt(expectedValue.items.length),
+        /Index out of range\./);
+    }
+  });
+});
--- a/browser/extensions/formautofill/test/unit/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 firefox-appdir = browser
 head = head.js
 tail =
 support-files =
 
 [test_autofillFormFields.js]
 [test_collectFormFields.js]
+[test_markAsAutofillField.js]
 [test_populateFieldValues.js]
+[test_profileAutocompleteResult.js]
 [test_profileStorage.js]
-[test_markAsAutofillField.js]