Bug 1360370 - Part 3: Implement the heuristics of select element for country and state prediction.; r?MattN draft
authorSean Lee <selee@mozilla.com>
Mon, 08 May 2017 17:41:03 +0800
changeset 586818 c280737876d7c96f425b5b1fba8bab7bede2d70c
parent 586817 af8dce14146cd079493395b73d13ba4531d67620
child 631109 814b574bdc953935fba31d280d2b1945b335bc4b
push id61534
push userbmo:selee@mozilla.com
push dateWed, 31 May 2017 04:27:14 +0000
reviewersMattN
bugs1360370
milestone55.0a1
Bug 1360370 - Part 3: Implement the heuristics of select element for country and state prediction.; r?MattN MozReview-Commit-ID: D8DAZrAF6H6
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/FormAutofillHeuristics.jsm
browser/extensions/formautofill/FormAutofillUtils.jsm
browser/extensions/formautofill/content/FormAutofillFrameScript.js
browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
browser/extensions/formautofill/test/unit/head.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js
browser/extensions/formautofill/test/unit/test_autofillFormFields.js
browser/extensions/formautofill/test/unit/test_collectFormFields.js
browser/extensions/formautofill/test/unit/test_getFormInputDetails.js
browser/extensions/formautofill/test/unit/test_getInfo.js
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -444,20 +444,18 @@ var FormAutofillContent = {
     if (!this.savedFieldNames) {
       this.log.debug("identifyAutofillFields: savedFieldNames are not known yet");
       Services.cpmm.sendAsyncMessage("FormAutofill:InitStorage");
     }
 
     let forms = [];
 
     // Collects root forms from inputs.
-    for (let field of doc.getElementsByTagName("input")) {
-      // We only consider text-like fields for now until we support radio and
-      // checkbox buttons in the future.
-      if (!field.mozIsTextField(true)) {
+    for (let field of FormAutofillUtils.autofillFieldSelector(doc)) {
+      if (!FormAutofillUtils.isFieldEligibleForAutofill(field)) {
         continue;
       }
 
       // For now skip consider fields in forms we've already seen before even
       // if the specific field wasn't seen before. Ideally whether the field is
       // already in the handler's form details would be considered.
       if (this.getFormHandler(field)) {
         continue;
@@ -486,17 +484,19 @@ var FormAutofillContent = {
       this.log.debug("Adding form handler to _formsDetails:", formHandler);
       formHandler.fieldDetails.forEach(detail =>
         this._markAsAutofillField(detail.elementWeakRef.get())
       );
     });
   },
 
   _markAsAutofillField(field) {
-    if (!field) {
+    // Since Form Autofill popup is only for input element, any non-Input
+    // element should be excluded here.
+    if (!field || !(field instanceof Ci.nsIDOMHTMLInputElement)) {
       return;
     }
 
     formFillController.markAsAutofillField(field);
   },
 
   _previewProfile(doc) {
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(doc.ownerGlobal);
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -86,17 +86,18 @@ FormAutofillHandler.prototype = {
       // 3. the invalid value set
 
       let element = fieldDetail.elementWeakRef.get();
       if (!element || element === focusedInput || element.value) {
         continue;
       }
 
       let value = profile[fieldDetail.fieldName];
-      if (value) {
+      // TODO: Bug 1364823 is implemeting the value filling of select element.
+      if (element instanceof Ci.nsIDOMHTMLInputElement && value) {
         element.setUserInput(value);
       }
     }
   },
 
   /**
    * Populates result to the preview layers with given profile.
    *
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -132,19 +132,17 @@ this.FormAutofillHeuristics = {
         result.fieldName = fieldName;
         return result;
       }
     }
     return null;
   },
 
   getInfo(element, fieldDetails) {
-    if (!(element instanceof Ci.nsIDOMHTMLInputElement) ||
-        !["text", "email", "tel", "number"].includes(element.type) ||
-        element.autocomplete == "off") {
+    if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
       return null;
     }
 
     let info = element.getAutocompleteInfo();
     // An input[autocomplete="on"] will not be early return here since it stll
     // needs to find the field name.
     if (info && info.fieldName && info.fieldName != "on") {
       return info;
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -57,16 +57,20 @@ this.FormAutofillUtils = {
       let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
       return new ConsoleAPI({
         maxLogLevelPref: "extensions.formautofill.loglevel",
         prefix: logPrefix,
       });
     });
   },
 
+  autofillFieldSelector(doc) {
+    return doc.querySelectorAll("input, select");
+  },
+
   ALLOWED_TYPES: ["text", "email", "tel", "number"],
   isFieldEligibleForAutofill(element) {
     if (element.autocomplete == "off") {
       return false;
     }
 
     if (element instanceof Ci.nsIDOMHTMLInputElement) {
       // `element.type` can be recognized as `text`, if it's missing or invalid.
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -10,16 +10,17 @@
 
 /* eslint-env mozilla/frame-script */
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://formautofill/FormAutofillContent.jsm");
+Cu.import("resource://formautofill/FormAutofillUtils.jsm");
 
 /**
  * Handles content's interactions for the frame.
  *
  * NOTE: Declares it by "var" to make it accessible in unit tests.
  */
 var FormAutofillFrameScript = {
   init() {
@@ -35,17 +36,17 @@ var FormAutofillFrameScript = {
 
     if (!Services.prefs.getBoolPref("extensions.formautofill.addresses.enabled")) {
       return;
     }
 
     switch (evt.type) {
       case "focusin": {
         let element = evt.target;
-        if (!(element instanceof Ci.nsIDOMHTMLInputElement)) {
+        if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
           return;
         }
         FormAutofillContent.identifyAutofillFields(element.ownerDocument);
         break;
       }
     }
   },
 
--- a/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
+++ b/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
@@ -20,20 +20,20 @@
   </form>
 
   <form id="formB">
     <p><label>Organization: <input type="text" /></label></p>
     <p><label><input type="text" id="B_address-line1" /></label></p>
     <p><label><input type="text" name="address-line2" /></label></p>
     <p><label><input type="text" id="B_address-line3" name="address-line3" /></label></p>
     <p><label>City: <input type="text" name="address-level2" /></label></p>
-    <p><label>State: <input type="text" id="B_address-level1" /></label></p>
+    <p><label>State: <select id="B_address-level1" ></select></label></p>
     <p><input type="text" id="B_postal-code" name="postal-code" /></p>
-    <p><label>Country: <input type="text" id="B_country" name="country" /></label></p>
-    <p><label>Telephone: <input type="text" id="B_tel" name="tel" /></label></p>
+    <p><label>Country: <select multiple id="B_country" name="country" ></select></label></p>
+    <p><label>Telephone: <input id="B_tel" name="tel" /></label></p>
     <p><label>Email: <input type="text" id="B_email" name="email" /></label></p>
     <p><input type="submit" /></p>
     <p><button type="reset">Reset</button></p>
   </form>
 
 </body>
 </html>
 
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -77,33 +77,30 @@ function getTempFile(leafName) {
   });
 
   return file;
 }
 
 function runHeuristicsTest(patterns, fixturePathPrefix) {
   Cu.import("resource://gre/modules/FormLikeFactory.jsm");
   Cu.import("resource://formautofill/FormAutofillHeuristics.jsm");
+  Cu.import("resource://formautofill/FormAutofillUtils.jsm");
 
-  // TODO: "select" and "textarea" will be included eventually.
-  const QUERY_STRING = ["input"];
   patterns.forEach(testPattern => {
     add_task(function* () {
       do_print("Starting test fixture: " + testPattern.fixturePath);
       let file = do_get_file(fixturePathPrefix + testPattern.fixturePath);
       let doc = MockDocument.createTestDocumentFromFile("http://localhost:8080/test/", file);
 
       let forms = [];
 
-      for (let query of QUERY_STRING) {
-        for (let field of doc.querySelectorAll(query)) {
-          let formLike = FormLikeFactory.createFromField(field);
-          if (!forms.some(form => form.rootElement === formLike.rootElement)) {
-            forms.push(formLike);
-          }
+      for (let field of FormAutofillUtils.autofillFieldSelector(doc)) {
+        let formLike = FormLikeFactory.createFromField(field);
+        if (!forms.some(form => form.rootElement === formLike.rootElement)) {
+          forms.push(formLike);
         }
       }
 
       Assert.equal(forms.length, testPattern.expectedResult.length, "Expected form count.");
 
       forms.forEach((form, formIndex) => {
         let formInfo = FormAutofillHeuristics.getFormInfo(form);
         do_print("FieldName Prediction Results: " + formInfo.map(i => i.fieldName));
@@ -116,15 +113,17 @@ function runHeuristicsTest(patterns, fix
       });
     });
   });
 }
 
 add_task(function* head_initialize() {
   Services.prefs.setBoolPref("extensions.formautofill.experimental", true);
   Services.prefs.setBoolPref("extensions.formautofill.heuristics.enabled", true);
+  Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", true);
 
   // Clean up after every test.
   do_register_cleanup(function head_cleanup() {
     Services.prefs.clearUserPref("extensions.formautofill.experimental");
     Services.prefs.clearUserPref("extensions.formautofill.heuristics.enabled");
+    Services.prefs.clearUserPref("dom.forms.autocomplete.experimental");
   });
 });
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js
@@ -7,17 +7,17 @@ runHeuristicsTest([
     fixturePath: "Checkout_ShippingAddress.html",
     expectedResult: [
       [], // Search form
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO:select,state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
       ],
       [ // Sign up
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [ // unknown
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
@@ -30,17 +30,17 @@ runHeuristicsTest([
       [ // Sign up
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO:select,state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
       ],
       [
         // unknown
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
       ],
     ],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
@@ -8,34 +8,34 @@ runHeuristicsTest([
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
       ],
       [],
     ],
   }, {
     fixturePath: "Checkout_BillingPaymentInfo.html",
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
       ],
       [
  /* TODO: Credit Card
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
@@ -8,35 +8,35 @@ runHeuristicsTest([
     expectedResult: [
       [],
       [],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select,country
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select,country
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
@@ -58,35 +58,35 @@ runHeuristicsTest([
       [],
       [],
       [],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js
@@ -8,16 +8,17 @@ runHeuristicsTest([
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+        {"section": "", "addressType": "billing", "contactType": "", "fieldName": "street-address"}, // <select>
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
       ],
     ],
   }, {
     fixturePath: "SignIn.html",
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
@@ -6,18 +6,18 @@ runHeuristicsTest([
   {
     fixturePath: "Checkout_ShippingAddress.html",
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
-        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // select
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
       ],
       [
 /*
 */
       ],
     ],
@@ -32,18 +32,18 @@ runHeuristicsTest([
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
 */
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
-        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // select
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [],
     ],
   }, {
     fixturePath: "SignIn.html",
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
@@ -4,21 +4,21 @@
 
 runHeuristicsTest([
   {
     fixturePath: "ShippingInfo.html",
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
       [],
     ],
   }, {
     fixturePath: "BillingInfo.html",
@@ -29,21 +29,21 @@ runHeuristicsTest([
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
 */
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, country
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"}, // TODO
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // TODO
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"}, // TODO
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"}, // TODO
       ],
       [],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js
@@ -9,17 +9,17 @@ runHeuristicsTest([
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
 
         // TODO: telphone relative fields should be fixed:
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-area-code"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-prefix"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-suffix"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
 
@@ -35,17 +35,17 @@ runHeuristicsTest([
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
 
         // TODO: telphone relative fields should be fixed:
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-area-code"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-prefix"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-suffix"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
 
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js
@@ -13,17 +13,17 @@ runHeuristicsTest([
       ],
       [ // check-out, ac-off
 /*
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
 */
       ],
       [ // ac-off
 /*
@@ -59,18 +59,18 @@ runHeuristicsTest([
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
       ],
       [ // Another billing address
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
-        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
       ],
       [ // check out
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: Wrong. This is for Driver's license.
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js
@@ -26,18 +26,18 @@ runHeuristicsTest([
     fixturePath: "Payment.html",
     expectedResult: [
       [
       ],
       [
         {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "cc-number"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+        {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+        {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
         {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "tel"},
       ],
     ],
   }, {
     fixturePath: "Shipping.html",
     expectedResult: [
       [
@@ -47,15 +47,15 @@ runHeuristicsTest([
       ],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
       ],
     ],
   },
 ], "../../../fixtures/third_party/Walmart/");
 
--- a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
@@ -5,17 +5,17 @@
 "use strict";
 
 Cu.import("resource://formautofill/FormAutofillHandler.jsm");
 
 const TESTCASES = [
   {
     description: "Form without autocomplete property",
     document: `<form><input id="given-name"><input id="family-name">
-               <input id="street-addr"><input id="city"><input id="country">
+               <input id="street-addr"><input id="city"><select id="country"></select>
                <input id='email'><input id="tel"></form>`,
     fieldDetails: [],
     profileData: {},
     expectedResult: {
       "street-addr": "",
       "city": "",
       "country": "",
       "email": "",
@@ -23,17 +23,17 @@ const TESTCASES = [
     },
   },
   {
     description: "Form with autocomplete properties and 1 token",
     document: `<form><input id="given-name" autocomplete="given-name">
                <input id="family-name" autocomplete="family-name">
                <input id="street-addr" autocomplete="street-address">
                <input id="city" autocomplete="address-level2">
-               <input id="country" autocomplete="country">
+               <select id="country" autocomplete="country"></select>
                <input id="email" autocomplete="email">
                <input id="tel" autocomplete="tel"></form>`,
     fieldDetails: [
       {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "country", "element": {}},
@@ -57,17 +57,17 @@ const TESTCASES = [
     },
   },
   {
     description: "Form with autocomplete properties and 2 tokens",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="shipping street-address">
                <input id="city" autocomplete="shipping address-level2">
-               <input id="country" autocomplete="shipping country">
+               <select id="country" autocomplete="shipping country"></select>
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
     fieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
@@ -170,18 +170,23 @@ for (let tc of TESTCASES) {
       let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
                                                 testcase.document);
       let form = doc.querySelector("form");
       let handler = new FormAutofillHandler(form);
       let onChangePromises = [];
 
       handler.fieldDetails = testcase.fieldDetails;
       handler.fieldDetails.forEach((field, index) => {
-        let element = doc.querySelectorAll("input")[index];
+        let element = doc.querySelectorAll("input, select")[index];
         field.elementWeakRef = Cu.getWeakReference(element);
+        if (element instanceof Ci.nsIDOMHTMLSelectElement) {
+          // TODO: Bug 1364823 should remove the condition and handle filling
+          // value in <select>
+          return;
+        }
         if (!testcase.profileData[field.fieldName]) {
           // Avoid waiting for `change` event of a input with a blank value to
           // be filled.
           return;
         }
         onChangePromises.push(new Promise(resolve => {
           element.addEventListener("change", () => {
             let id = element.id;
--- a/browser/extensions/formautofill/test/unit/test_collectFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_collectFormFields.js
@@ -5,17 +5,17 @@
 "use strict";
 
 Cu.import("resource://formautofill/FormAutofillHandler.jsm");
 
 const TESTCASES = [
   {
     description: "Form without autocomplete property",
     document: `<form><input id="given-name"><input id="family-name">
-               <input id="street-addr"><input id="city"><input id="country">
+               <input id="street-addr"><input id="city"><select id="country"></select>
                <input id='email'><input id="tel"></form>`,
     fieldDetails: [
       {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
@@ -24,17 +24,17 @@ const TESTCASES = [
     ids: ["given-name", "family-name", "street-addr", "city", "country", "email", "tel"],
   },
   {
     description: "Form with autocomplete properties and 1 token",
     document: `<form><input id="given-name" autocomplete="given-name">
                <input id="family-name" autocomplete="family-name">
                <input id="street-addr" autocomplete="street-address">
                <input id="city" autocomplete="address-level2">
-               <input id="country" autocomplete="country">
+               <select id="country" autocomplete="country"></select>
                <input id="email" autocomplete="email">
                <input id="tel" autocomplete="tel"></form>`,
     fieldDetails: [
       {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
@@ -61,18 +61,18 @@ const TESTCASES = [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel"},
     ],
   },
   {
     description: "Form with autocomplete properties and profile is partly matched",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="shipping street-address">
-               <input id="city" autocomplete="shipping address-level2">
-               <input id="country" autocomplete="shipping country">
+               <input autocomplete="shipping address-level2">
+               <select autocomplete="shipping country"></select>
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
     fieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country"},
@@ -92,17 +92,17 @@ for (let tc of TESTCASES) {
                                                 testcase.document);
       let form = doc.querySelector("form");
 
       testcase.fieldDetails.forEach((detail, index) => {
         let elementRef;
         if (testcase.ids && testcase.ids[index]) {
           elementRef = doc.getElementById(testcase.ids[index]);
         } else {
-          elementRef = doc.querySelector("input[autocomplete*='" + detail.fieldName + "']");
+          elementRef = doc.querySelector("*[autocomplete*='" + detail.fieldName + "']");
         }
         detail.elementWeakRef = Cu.getWeakReference(elementRef);
       });
       let handler = new FormAutofillHandler(form);
 
       handler.collectFormFields();
 
       handler.fieldDetails.forEach((detail, index) => {
--- a/browser/extensions/formautofill/test/unit/test_getFormInputDetails.js
+++ b/browser/extensions/formautofill/test/unit/test_getFormInputDetails.js
@@ -3,50 +3,50 @@
 Cu.import("resource://formautofill/FormAutofillContent.jsm");
 
 const TESTCASES = [
   {
     description: "Form containing 5 fields with autocomplete attribute.",
     document: `<form id="form1">
                  <input id="street-addr" autocomplete="street-address">
                  <input id="city" autocomplete="address-level2">
-                 <input id="country" autocomplete="country">
+                 <select id="country" autocomplete="country"></select>
                  <input id="email" autocomplete="email">
                  <input id="tel" autocomplete="tel">
                </form>`,
-    targetInput: ["street-addr", "country"],
+    targetInput: ["street-addr", "email"],
     expectedResult: [{
       input: {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
       formId: "form1",
       form: [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
       ],
     },
     {
-      input: {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
+      input: {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       formId: "form1",
       form: [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
       ],
     }],
   },
   {
     description: "2 forms that are able to be auto filled",
     document: `<form id="form2">
                  <input id="home-addr" autocomplete="street-address">
                  <input id="city" autocomplete="address-level2">
-                 <input id="country" autocomplete="country">
+                 <select id="country" autocomplete="country"></select>
                </form>
                <form id="form3">
                  <input id="office-addr" autocomplete="street-address">
                  <input id="email" autocomplete="email">
                  <input id="tel" autocomplete="tel">
                </form>`,
     targetInput: ["home-addr", "office-addr"],
     expectedResult: [{
@@ -93,19 +93,19 @@ TESTCASES.forEach(testcase => {
       // `getInputDetails` contains the same input element.
       testcase.expectedResult[i].input.elementWeakRef = Cu.getWeakReference(input);
 
       inputDetailAssertion(FormAutofillContent.getInputDetails(input),
                            testcase.expectedResult[i].input);
 
       let formDetails = testcase.expectedResult[i].form;
       for (let formDetail of formDetails) {
-        // Compose a query string to get the exact reference of the input
-        // element, e.g. #form1 > input[autocomplete="street-address"]
-        let queryString = "#" + testcase.expectedResult[i].formId + " > input[autocomplete=" + formDetail.fieldName + "]";
+        // Compose a query string to get the exact reference of <input>/<select>
+        // element, e.g. #form1 > *[autocomplete="street-address"]
+        let queryString = "#" + testcase.expectedResult[i].formId + " > *[autocomplete=" + formDetail.fieldName + "]";
         formDetail.elementWeakRef = Cu.getWeakReference(doc.querySelector(queryString));
       }
 
       FormAutofillContent.getFormDetails(input).forEach((detail, index) => {
         inputDetailAssertion(detail, formDetails[index]);
       });
     }
   });
--- a/browser/extensions/formautofill/test/unit/test_getInfo.js
+++ b/browser/extensions/formautofill/test/unit/test_getInfo.js
@@ -64,16 +64,43 @@ const TESTCASES = [
     expectedReturnValue: {
       fieldName: "email",
       section: "",
       addressType: "",
       contactType: "",
     },
   },
   {
+    description: "Select element in a label element",
+    document: `<form>
+                 <label> State
+                   <select id="targetElement"></select>
+                 </label>
+               </form>`,
+    elementId: "targetElement",
+    expectedReturnValue: {
+      fieldName: "address-level1",
+      section: "",
+      addressType: "",
+      contactType: "",
+    },
+  },
+  {
+    description: "A select element without a form wrapped",
+    document: `<label for="targetElement">State</label>
+               <select id="targetElement"></select>`,
+    elementId: "targetElement",
+    expectedReturnValue: {
+      fieldName: "address-level1",
+      section: "",
+      addressType: "",
+      contactType: "",
+    },
+  },
+  {
     description: "2 address line inputs",
     document: `<label for="targetElement">street</label>
                <input id="targetElement" type="text">`,
     elementId: "targetElement",
     fieldDetails: [{fieldName: "address-line1"}],
     expectedReturnValue: {
       fieldName: "address-line2",
       section: "",