Bug 1349490 - Part 1: Implement FormAutofillUtil.extractLabelStrings function.; r=MattN
authorSean Lee <selee@mozilla.com>
Mon, 24 Apr 2017 22:30:37 +0800
changeset 409534 862c6eb8b0e3bf1600e63dc7cefd442eb80486a4
parent 409533 c11a042b597c24a2b24e1eab57676dd08aac2c5d
child 409535 3c62252be2db131d09cc38838642b7d10788b946
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1349490
milestone55.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 1349490 - Part 1: Implement FormAutofillUtil.extractLabelStrings function.; r=MattN MozReview-Commit-ID: 9kCZkgnqOfF
browser/extensions/formautofill/FormAutofillUtils.jsm
browser/extensions/formautofill/test/unit/test_extractLabelStrings.js
browser/extensions/formautofill/test/unit/xpcshell.ini
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -57,16 +57,58 @@ this.FormAutofillUtils = {
       let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
       return new ConsoleAPI({
         maxLogLevelPref: "extensions.formautofill.loglevel",
         prefix: logPrefix,
       });
     });
   },
 
+  // The tag name list is from Chromium except for "STYLE":
+  // eslint-disable-next-line max-len
+  // https://cs.chromium.org/chromium/src/components/autofill/content/renderer/form_autofill_util.cc?l=216&rcl=d33a171b7c308a64dc3372fac3da2179c63b419e
+  EXCLUDED_TAGS: ["SCRIPT", "NOSCRIPT", "OPTION", "STYLE"],
+  /**
+   * Extract all strings of an element's children to an array.
+   * "element.textContent" is a string which is merged of all children nodes,
+   * and this function provides an array of the strings contains in an element.
+   *
+   * @param  {Object} element
+   *         A DOM element to be extracted.
+   * @returns {Array}
+   *          All strings in an element.
+   */
+  extractLabelStrings(element) {
+    let strings = [];
+    let _extractLabelStrings = (el) => {
+      if (this.EXCLUDED_TAGS.includes(el.tagName)) {
+        return;
+      }
+
+      if (el.nodeType == Ci.nsIDOMNode.TEXT_NODE ||
+          el.childNodes.length == 0) {
+        let trimmedText = el.textContent.trim();
+        if (trimmedText) {
+          strings.push(trimmedText);
+        }
+        return;
+      }
+
+      for (let node of el.childNodes) {
+        if (node.nodeType != Ci.nsIDOMNode.ELEMENT_NODE &&
+            node.nodeType != Ci.nsIDOMNode.TEXT_NODE) {
+          continue;
+        }
+        _extractLabelStrings(node);
+      }
+    };
+    _extractLabelStrings(element);
+    return strings;
+  },
+
   findLabelElements(element) {
     let document = element.ownerDocument;
     let labels = [];
     // TODO: querySelectorAll is inefficient here. However, bug 1339726 is for
     // a more efficient implementation from DOM API perspective. This function
     // should be refined after input.labels API landed.
     for (let label of document.querySelectorAll("label[for]")) {
       if (element.id == label.htmlFor) {
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/test_extractLabelStrings.js
@@ -0,0 +1,66 @@
+"use strict";
+
+Cu.import("resource://formautofill/FormAutofillUtils.jsm");
+
+const TESTCASES = [
+  {
+    description: "A label element contains one input element.",
+    document: `<label id="typeA"> label type A
+                 <!-- This comment should not be extracted. -->
+                 <input type="text">
+                 <script>FOO</script>
+                 <noscript>FOO</noscript>
+                 <option>FOO</option>
+                 <style>FOO</style>
+               </label>`,
+    inputId: "typeA",
+    expectedStrings: ["label type A"],
+  },
+  {
+    description: "A label element with inner div contains one input element.",
+    document: `<label id="typeB"> label type B
+                 <!-- This comment should not be extracted. -->
+                 <script>FOO</script>
+                 <noscript>FOO</noscript>
+                 <option>FOO</option>
+                 <style>FOO</style>
+                 <div> inner div
+                   <input type="text">
+                 </div>
+               </label>`,
+    inputId: "typeB",
+    expectedStrings: ["label type B", "inner div"],
+  },
+  {
+    description: "A label element with inner prefix/postfix strings contains span elements.",
+    document: `<label id="typeC"> label type C
+                 <!-- This comment should not be extracted. -->
+                 <script>FOO</script>
+                 <noscript>FOO</noscript>
+                 <option>FOO</option>
+                 <style>FOO</style>
+                 <div> inner div prefix
+                   <span>test C-1 </span>
+                   <span> test C-2</span>
+                  inner div postfix
+                 </div>
+               </label>`,
+    inputId: "typeC",
+    expectedStrings: ["label type C", "inner div prefix", "test C-1",
+      "test C-2", "inner div postfix"],
+  },
+];
+
+TESTCASES.forEach(testcase => {
+  add_task(function* () {
+    do_print("Starting testcase: " + testcase.description);
+
+    let doc = MockDocument.createTestDocument(
+      "http://localhost:8080/test/", testcase.document);
+
+    let element = doc.getElementById(testcase.inputId);
+    let strings = FormAutofillUtils.extractLabelStrings(element);
+
+    Assert.deepEqual(strings, testcase.expectedStrings);
+  });
+});
--- a/browser/extensions/formautofill/test/unit/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/xpcshell.ini
@@ -16,16 +16,17 @@ support-files =
 [heuristics/third_party/test_Sears.js]
 [heuristics/third_party/test_Staples.js]
 [heuristics/third_party/test_Walmart.js]
 [test_activeStatus.js]
 [test_addressRecords.js]
 [test_autofillFormFields.js]
 [test_collectFormFields.js]
 [test_creditCardRecords.js]
+[test_extractLabelStrings.js]
 [test_findLabelElements.js]
 [test_getCategoriesFromFieldNames.js]
 [test_getFormInputDetails.js]
 [test_isCJKName.js]
 [test_markAsAutofillField.js]
 [test_nameUtils.js]
 [test_onFormSubmitted.js]
 [test_profileAutocompleteResult.js]