Bug 1548381 - Tests for the password generation autocomplete UI. r=sfoster
☠☠ backed out by 2690e619a493 ☠ ☠
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Mon, 20 May 2019 19:56:27 +0000
changeset 474626 0e7d8f96bf123f5d0f491fe7780223bde509e841
parent 474625 738ce5e88e05ae37464b0e94889a5156c5497435
child 474627 a8bd87bfc775789e75c9c8721ffb681121c4f100
push id36042
push userdvarga@mozilla.com
push dateTue, 21 May 2019 04:19:40 +0000
treeherdermozilla-central@ca560ff55451 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster
bugs1548381
milestone69.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 1548381 - Tests for the password generation autocomplete UI. r=sfoster Differential Revision: https://phabricator.services.mozilla.com/D31576
toolkit/components/passwordmgr/test/mochitest/pwmgr_common.js
toolkit/components/passwordmgr/test/mochitest/test_autocomplete_new_password.html
--- a/toolkit/components/passwordmgr/test/mochitest/pwmgr_common.js
+++ b/toolkit/components/passwordmgr/test/mochitest/pwmgr_common.js
@@ -1,14 +1,16 @@
 /**
  * Helpers for password manager mochitest-plain tests.
  */
 
 /* import-globals-from ../../../../../toolkit/components/satchel/test/satchel_common.js */
 
+const GENERATED_PASSWORD_LENGTH = 15;
+const GENERATED_PASSWORD_REGEX = /^[a-km-np-zA-HJ-NP-Z2-9]{15}$/;
 // Copied from LoginTestUtils.masterPassword.masterPassword to use from the content process.
 const MASTER_PASSWORD = "omgsecret!";
 const TESTS_DIR = "/tests/toolkit/components/passwordmgr/test/";
 
 /**
  * Returns the element with the specified |name| attribute.
  */
 function $_(formNum, name) {
@@ -223,16 +225,17 @@ function logoutMasterPassword() {
  * Resolves when a specified number of forms have been processed for (potential) filling.
  */
 function promiseFormsProcessed(expectedCount = 1) {
   var processedCount = 0;
   return new Promise((resolve, reject) => {
     function onProcessedForm(subject, topic, data) {
       processedCount++;
       if (processedCount == expectedCount) {
+        info(`${processedCount} form(s) processed`);
         SpecialPowers.removeObserver(onProcessedForm, "passwordmgr-processed-form");
         resolve(SpecialPowers.Cu.waiveXrays(subject), data);
       }
     }
     SpecialPowers.addObserver(onProcessedForm, "passwordmgr-processed-form");
   });
 }
 
--- a/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_new_password.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_new_password.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
-  <title>Test autofill with autocomplete=new-password fields</title>
+  <title>Test autofill and autocomplete on autocomplete=new-password fields</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="/tests/SimpleTest/EventUtils.js"></script>
   <script src="pwmgr_common.js"></script>
   <script src="../../../satchel/test/satchel_common.js"></script>
   <link rel="stylesheet" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Login Manager test: autofill with autocomplete=new-password fields
@@ -33,51 +33,168 @@ let readyPromise = registerRunTests();
 
   <!-- form1 is the reference, sanity-check -->
   <form id="form1" action="https://autofill" onsubmit="return false;">
     <input type="text" name="uname">
     <input type="password" name="p">
     <button type="submit">Submit</button>
   </form>
 
-  <!-- form2 uses the new-password field -->
+  <!-- form2 uses a new-password type=password field -->
   <form id="form2" action="https://autofill" onsubmit="return false;">
     <input type="text" name="uname">
-    <input type="password" autocomplete="new-password">
+    <input type="password" name="pword" autocomplete="new-password">
     <button type="submit">Submit</button>
   </form>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 const {ContentTaskUtils} =
   SpecialPowers.Cu.import("resource://testing-common/ContentTaskUtils.jsm", {});
 
-async function fillFirstAutocompleteResult(input) {
-  const shownPromise = promiseACShown();
-  synthesizeKey("KEY_ArrowDown");
-  await shownPromise;
-  synthesizeKey("KEY_ArrowDown");
-  await synthesizeKey("KEY_Enter");
-}
-
 add_task(async function setup() {
   ok(readyPromise, "check promise is available");
   await readyPromise;
 });
 
-add_task(async function test_autofillAutocompleteNewPassword() {
+add_task(async function test_autofillAutocompleteUsername_noGeneration() {
   // reference form was filled as expected?
   checkForm(1, "user1", "pass1");
 
   // 2nd form should not be filled
   checkForm(2, "", "");
 
   $_(2, "uname").focus();
-  await fillFirstAutocompleteResult();
+  const shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown");
+  let results = await shownPromise;
+  let expectedACLabels = ["user1"];
+  checkAutoCompleteResults(results, expectedACLabels, "example.com", "Check all rows are correct");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_Enter");
+  await promiseFormsProcessed();
+  checkForm(2, "user1", "pass1");
+
+  document.getElementById("form2").reset();
+});
+
+add_task(async function test_autofillAutocompletePassword_noGeneration() {
+  // 2nd form should not be filled
+  checkForm(2, "", "");
+
+  let pword = $_(2, "pword");
+  pword.focus();
+  const shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown");
+  let results = await shownPromise;
+  let expectedACLabels = ["user1"];
+  checkAutoCompleteResults(results, expectedACLabels, "example.com", "Check all rows are correct");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_Enter");
+  // Can't use promiseFormsProcessed() when autocomplete fills the field directly.
+  await SimpleTest.promiseWaitForCondition(() => pword.value == "pass1", "Check pw filled");
+  checkForm(2, "", "pass1");
+
+  // No autocomplete results should appear for non-empty pw fields.
+  synthesizeKey("KEY_ArrowDown");
+  await promiseNoUnexpectedPopupShown();
+
+  document.getElementById("form2").reset();
+});
+
+// All tests below this are with generation prefs enabled.
+
+add_task(async function test_autofillAutocompleteUsername_noGeneration() {
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["signon.generation.available", true],
+    ["signon.generation.enabled", true],
+    ["signon.showAutoCompleteOrigins", true],
+  ]});
+
+  // 2nd form should not be filled
+  checkForm(2, "", "");
+
+  $_(2, "uname").focus();
+  const shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown");
+  let results = await shownPromise;
+  // No generation option on username fields.
+  let expectedACLabels = ["user1"];
+  checkAutoCompleteResults(results, expectedACLabels, "example.com", "Check all rows are correct");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_Enter");
   await promiseFormsProcessed();
   checkForm(2, "user1", "pass1");
+
+  document.getElementById("form2").reset();
 });
 
+add_task(async function test_autofillAutocompletePassword_withGeneration() {
+  // 2nd form should not be filled
+  checkForm(2, "", "");
+
+  let pword = $_(2, "pword");
+  pword.focus();
+  let shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown");
+  let results = await shownPromise;
+  let expectedACLabels = [
+    "user1",
+    "Use Generated Password",
+  ];
+  checkAutoCompleteResults(results, expectedACLabels, "example.com", "Check all rows are correct");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_Enter");
+  // Can't use promiseFormsProcessed() when autocomplete fills the field directly.
+  await SimpleTest.promiseWaitForCondition(() => pword.value == "pass1", "Check pw filled");
+  checkForm(2, "", "pass1");
+
+  // No autocomplete results should appear for non-empty pw fields.
+  synthesizeKey("KEY_ArrowDown");
+  await promiseNoUnexpectedPopupShown();
+
+  while (pword.value) {
+    synthesizeKey("KEY_Backspace");
+  }
+
+  info("This time select the generated password");
+  shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown");
+  results = await shownPromise;
+  expectedACLabels = [
+    "user1",
+    "Use Generated Password",
+  ];
+  checkAutoCompleteResults(results, expectedACLabels, "example.com", "Check all rows are correct");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_Enter");
+  await SimpleTest.promiseWaitForCondition(() => !!pword.value, "Check generated pw filled");
+  let generatedPW = pword.value;
+  is(generatedPW.length, GENERATED_PASSWORD_LENGTH, "Check generated password length");
+  ok(generatedPW.match(GENERATED_PASSWORD_REGEX), "Check generated password format");
+
+  while (pword.value) {
+    synthesizeKey("KEY_Backspace");
+  }
+
+  shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown");
+  results = await shownPromise;
+  expectedACLabels = [
+    "user1",
+    "Use Generated Password",
+  ];
+  checkAutoCompleteResults(results, expectedACLabels, "example.com", "Check all rows are correct");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_Enter");
+  await SimpleTest.promiseWaitForCondition(() => !!pword.value, "Check generated pw filled");
+  // Same generated password should be used.
+  checkForm(2, "", generatedPW);
+
+  document.getElementById("form2").reset();
+});
 </script>
 </pre>
 </body>
 </html>