Bug 1548381 - Tests for the password generation autocomplete UI. r=sfoster
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Tue, 21 May 2019 00:24:16 +0000
changeset 474670 b74e5737da64a7af28ab4f81f996950917aa71c5
parent 474669 34bbe924602e6a465a34498f6e6e2f3f767ccddc
child 474671 441a4c70ac221317eaf998f43dc8b2cdcb06cd2b
child 474729 f3fae269992d4984480f731765bd7040def16c60
push id36043
push userrmaries@mozilla.com
push dateTue, 21 May 2019 09:44:47 +0000
treeherdermozilla-central@b74e5737da64 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster
bugs1548381
milestone69.0a1
first release with
nightly linux32
b74e5737da64 / 69.0a1 / 20190521094447 / files
nightly linux64
b74e5737da64 / 69.0a1 / 20190521094447 / files
nightly mac
b74e5737da64 / 69.0a1 / 20190521094447 / files
nightly win32
b74e5737da64 / 69.0a1 / 20190521094447 / files
nightly win64
b74e5737da64 / 69.0a1 / 20190521094447 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
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>