Bug 1304634 - Part 4: Apply form autofill API and add mochitest, r=MattN draft
authorSteve Chung <schung@mozilla.com>
Thu, 10 Nov 2016 18:01:38 +0800
changeset 452758 33e96ca93791dc7143eb3a1d637c483b87d3fcfc
parent 452757 aa89d7460989f3574a09d524b5a8aff55e7add33
child 540287 99d37901d7522872d6ebd3a3ac80915fedd77981
push id39470
push userschung@mozilla.com
push dateThu, 22 Dec 2016 04:09:07 +0000
reviewersMattN
bugs1304634
milestone53.0a1
Bug 1304634 - Part 4: Apply form autofill API and add mochitest, r=MattN -Commit-ID: 5eHRYoMbH7J MozReview-Commit-ID: 47EnZ5Oyf88
browser/extensions/formautofill/moz.build
browser/extensions/formautofill/test/mochitest/formautofill_common.js
browser/extensions/formautofill/test/mochitest/mochitest.ini
browser/extensions/formautofill/test/mochitest/parent_utils.js
browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
testing/profiles/prefs_general.js
--- a/browser/extensions/formautofill/moz.build
+++ b/browser/extensions/formautofill/moz.build
@@ -14,12 +14,14 @@ FINAL_TARGET_FILES.features['formautofil
 FINAL_TARGET_PP_FILES.features['formautofill@mozilla.org'] += [
   'install.rdf.in'
 ]
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
 
+MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
+
 JAR_MANIFESTS += ['jar.mn']
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'Form Manager')
copy from toolkit/components/satchel/test/satchel_common.js
copy to browser/extensions/formautofill/test/mochitest/formautofill_common.js
--- a/toolkit/components/satchel/test/satchel_common.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_common.js
@@ -1,16 +1,18 @@
 /* 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/. */
 
 var gPopupShownExpected = false;
 var gPopupShownListener;
 var gLastAutoCompleteResults;
 var gChromeScript;
+var controller = SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].
+                      getService(SpecialPowers.Ci.nsIFormFillController);
 
 /*
  * Returns the element with the specified |name| attribute.
  */
 function $_(formNum, name) {
   var form = document.getElementById("form" + formNum);
   if (!form) {
     ok(false, "$_ couldn't find requested form " + formNum);
@@ -67,28 +69,37 @@ function getMenuEntries() {
     throw new Error("no autocomplete results");
   }
 
   var results = gLastAutoCompleteResults;
   gLastAutoCompleteResults = null;
   return results;
 }
 
+function checkMenuEntries(expectedValues) {
+    var actualValues = getMenuEntries();
+
+    is(actualValues.length, expectedValues.length, " Checking length of expected menu");
+    for (var i = 0; i < expectedValues.length; i++)
+        is(actualValues[i], expectedValues[i], " Checking menu entry #" + i);
+}
+
 function checkArrayValues(actualValues, expectedValues, msg) {
   is(actualValues.length, expectedValues.length, "Checking array values: " + msg);
   for (var i = 0; i < expectedValues.length; i++)
     is(actualValues[i], expectedValues[i], msg + " Checking array entry #" + i);
 }
 
 var checkObserver = {
   verifyStack: [],
   callback: null,
 
   init() {
     gChromeScript.sendAsyncMessage("addObserver");
+    // TODO: We don't have changed event right now, but it might be necessary for preference
     gChromeScript.addMessageListener("satchel-storage-changed", this.observe.bind(this));
   },
 
   uninit() {
     gChromeScript.sendAsyncMessage("removeObserver");
   },
 
   waitForChecks: function(callback) {
@@ -159,34 +170,19 @@ function countEntries(name, value, then 
       if (then) {
         then(data.count);
       }
       resolve(data.count);
     });
   });
 }
 
-// Wrapper around FormHistory.update which handles errors. Calls then() when done.
-function updateFormHistory(changes, then = null) {
-  return new Promise(resolve => {
-    gChromeScript.sendAsyncMessage("updateFormHistory", { changes });
-    gChromeScript.addMessageListener("formHistoryUpdated", function updated({ ok }) {
-      gChromeScript.removeMessageListener("formHistoryUpdated", updated);
-      if (!ok) {
-        ok(false, "Error occurred updating form history");
-        SimpleTest.finish();
-        return;
-      }
-
-      if (then) {
-        then();
-      }
-      resolve();
-    });
-  });
+// Wrapper around profile storage update which handles errors. Calls then() when done.
+function updateProfileStorage(changes, then = null) {
+  // TODO: Update profile
 }
 
 function notifyMenuChanged(expectedCount, expectedFirstValue, then = null) {
   return new Promise(resolve => {
     gChromeScript.sendAsyncMessage("waitForMenuChange",
                             { expectedCount,
                               expectedFirstValue });
     gChromeScript.addMessageListener("gotMenuChange", function changed({ results }) {
@@ -243,25 +239,32 @@ function promiseACShown() {
   return new Promise(resolve => {
     gChromeScript.addMessageListener("onpopupshown", ({ results }) => {
       gPopupShownExpected = false;
       resolve(results);
     });
   });
 }
 
-function satchelCommonSetup() {
+function markAsAutofillField(element) {
+  controller.markAsAutofillField(element);
+}
+
+function formAutoFillCommonSetup() {
   var chromeURL = SimpleTest.getTestFileURL("parent_utils.js");
   gChromeScript = SpecialPowers.loadChromeScript(chromeURL);
+  SpecialPowers.setBoolPref("dom.forms.autocomplete.experimental", true);
+
   gChromeScript.addMessageListener("onpopupshown", ({ results }) => {
     gLastAutoCompleteResults = results;
     if (gPopupShownListener)
       gPopupShownListener();
   });
 
   SimpleTest.registerCleanupFunction(() => {
+    SpecialPowers.clearUserPref("dom.forms.autocomplete.experimental");
     gChromeScript.sendAsyncMessage("cleanup");
     gChromeScript.destroy();
   });
 }
 
 
-satchelCommonSetup();
+formAutoFillCommonSetup();
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/mochitest/mochitest.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+skip-if = toolkit == 'android'
+support-files =
+  formautofill_common.js
+  parent_utils.js
+
+[test_basic_autocomplete_form.html]
+
copy from toolkit/components/satchel/test/parent_utils.js
copy to browser/extensions/formautofill/test/mochitest/parent_utils.js
--- a/toolkit/components/satchel/test/parent_utils.js
+++ b/browser/extensions/formautofill/test/mochitest/parent_utils.js
@@ -1,11 +1,11 @@
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
-Cu.import("resource://gre/modules/FormHistory.jsm");
+Cu.import("resource://formautofill/FormAutofillParent.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://testing-common/ContentTaskUtils.jsm");
 
 var gAutocompletePopup = Services.ww.activeWindow.
                                    document.
                                    getElementById("PopupAutoComplete");
 assert.ok(gAutocompletePopup, "Got autocomplete popup");
 
@@ -14,32 +14,22 @@ var ParentUtils = {
     let entries = [];
     let numRows = gAutocompletePopup.view.matchCount;
     for (let i = 0; i < numRows; i++) {
       entries.push(gAutocompletePopup.view.getValueAt(i));
     }
     return entries;
   },
 
-  cleanUpFormHist() {
-    FormHistory.update({ op: "remove" });
+  cleanUpProfile() {
+    //TODO: Call profile storage clean up API
   },
 
-  updateFormHistory(changes) {
-    let handler = {
-      handleError: function(error) {
-        assert.ok(false, error);
-        sendAsyncMessage("formHistoryUpdated", { ok: false });
-      },
-      handleCompletion: function(reason) {
-        if (!reason)
-          sendAsyncMessage("formHistoryUpdated", { ok: true });
-      },
-    };
-    FormHistory.update(changes, handler);
+  updateProfile(changes) {
+    //TODO: Call profile storage update API
   },
 
   popupshownListener() {
     let results = this.getMenuEntries();
     sendAsyncMessage("onpopupshown", { results });
   },
 
   countEntries(name, value) {
@@ -58,17 +48,17 @@ var ParentUtils = {
       },
       handleCompletion(reason) {
         if (!reason) {
           sendAsyncMessage("entriesCounted", { ok: true, count });
         }
       }
     };
 
-    FormHistory.count(obj, listener);
+    //TODO: Call profile storage count API
   },
 
   checkRowCount(expectedCount, expectedFirstValue = null) {
     ContentTaskUtils.waitForCondition(() => {
       // This may be called before gAutocompletePopup has initialised
       // which causes it to throw
       try {
         return gAutocompletePopup.view.matchCount === expectedCount &&
@@ -103,27 +93,27 @@ var ParentUtils = {
 
   observe(subject, topic, data) {
     assert.ok(topic === "satchel-storage-changed");
     sendAsyncMessage("satchel-storage-changed", { subject: null, topic, data });
   },
 
   cleanup() {
     gAutocompletePopup.removeEventListener("popupshown", this._popupshownListener);
-    this.cleanUpFormHist();
+    this.cleanUpProfile();
   }
 };
 
 ParentUtils._popupshownListener =
   ParentUtils.popupshownListener.bind(ParentUtils);
 gAutocompletePopup.addEventListener("popupshown", ParentUtils._popupshownListener);
-ParentUtils.cleanUpFormHist();
+ParentUtils.cleanUpProfile();
 
-addMessageListener("updateFormHistory", (msg) => {
-  ParentUtils.updateFormHistory(msg.changes);
+addMessageListener("updateProfile", (msg) => {
+  ParentUtils.updateProfile(msg.changes);
 });
 
 addMessageListener("countEntries", ({ name, value }) => {
   ParentUtils.countEntries(name, value);
 });
 
 addMessageListener("waitForMenuChange", ({ expectedCount, expectedFirstValue }) => {
   ParentUtils.checkRowCount(expectedCount, expectedFirstValue);
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test basic autofill</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="formautofill_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Form autofill test: simple form profile autofill
+
+<script>
+
+var expectingPopup = null;
+
+function expectPopup() {
+  info("expecting a popup");
+  return new Promise(resolve => {
+    expectingPopup = resolve;
+  });
+}
+
+function popupShownListener() {
+  info("popup shown for test ");
+  if (expectingPopup) {
+    expectingPopup();
+    expectingPopup = null;
+  }
+}
+
+function setInput(input, value) {
+  input.value = value;
+  input.focus();
+}
+
+function setupTest(id, str) {
+  let element = document.getElementById(id);
+  markAsAutofillField(element);
+  setInput(element, str);
+}
+
+function* runTests() {
+  setupTest("name", "");
+  doKey("down");
+  yield expectPopup();
+  checkMenuEntries(["Mary", "John"]);
+
+  setupTest("address", "");
+  doKey("down");
+  yield expectPopup();
+  checkMenuEntries(["Mary", "John"]);
+
+  setupTest("tel", "");
+  doKey("down");
+  yield expectPopup();
+  checkMenuEntries(["Mary", "John"]);
+
+  SimpleTest.finish();
+}
+
+function startTest() {
+  //TODO: Setup storage
+  spawn_task(runTests);
+}
+
+registerPopupShownListener(popupShownListener);
+SimpleTest.waitForExplicitFinish();
+window.onload = startTest;
+
+</script>
+
+<p id="display"></p>
+
+<div id="content">
+
+  <form id="form1">
+    <p>This is form 1.</p>
+    <input type="text" id="name"><br>
+    <input type="text" id="address"><br>
+    <input type="text" id="tel">
+  </form>
+
+</div>
+
+<pre id="test"></pre>
+</body>
+</html>
+
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -352,8 +352,11 @@ user_pref("plugin.load_flash_only", fals
 // cannot easily be upgraded.
 user_pref("media.libavcodec.allow-obsolete", true);
 
 user_pref("media.openUnsupportedTypeWithExternalApp", false);
 
 // Disable password capture, so that mochitests that include forms aren't
 // influenced by the presence of the persistent doorhanger notification.
 user_pref("signon.rememberSignons", false);
+
+// Enable form autofill feature testing.
+user_pref("browser.formautofill.enabled", true);