summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_password_generation.html
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/test/mochitest/test_autocomplete_password_generation.html')
-rw-r--r--toolkit/components/passwordmgr/test/mochitest/test_autocomplete_password_generation.html596
1 files changed, 596 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_password_generation.html b/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_password_generation.html
new file mode 100644
index 0000000000..3fd8b1e90b
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_password_generation.html
@@ -0,0 +1,596 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <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>
+<p id="display"></p>
+<div id="content"></div>
+<pre id="test">
+Login Manager test: autofill with password generation on `autocomplete=new-password` fields.
+
+<template id="form1-template">
+ <form id="form1" action="https://autofill">
+ <input type="text" name="uname">
+ <input type="password" name="p">
+ <button type="submit" name="submit">Submit</button>
+ </form>
+</template>
+
+<template id="form2-template">
+ <form id="form2" action="https://autofill">
+ <input type="text" name="uname">
+ <input type="password" name="password" autocomplete="new-password">
+ <button type="submit" name="submit">Submit</button>
+ </form>
+</template>
+
+<template id="form3-template">
+ <form id="form3" action="https://autofill">
+ <input type="text" name="username">
+ <label>New password<input type="password" name="password"></label>
+ <button type="submit" name="submit">Submit</button>
+ </form>
+</template>
+
+<script class="testbody" type="text/javascript">
+ const { TestUtils } = SpecialPowers.ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+ );
+
+ const formTemplates = {
+ form1: document.getElementById("form1-template"),
+ form2: document.getElementById("form2-template"),
+ form3: document.getElementById("form3-template"),
+ };
+
+ const dateAndTimeFormatter = new SpecialPowers.Services.intl.DateTimeFormat(undefined, {
+ dateStyle: "medium",
+ });
+
+ async function showACPopup(formNumber, expectedACLabels) {
+ const autocompleteItems = await popupByArrowDown();
+ checkAutoCompleteResults(autocompleteItems, expectedACLabels,
+ window.location.host, "Check all rows are correct");
+ }
+
+ function clearGeneratedPasswords() {
+ const { LoginManagerParent } = ChromeUtils.importESModule(
+ "resource://gre/modules/LoginManagerParent.sys.mjs"
+ );
+ if (LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin()) {
+ LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
+ }
+ }
+
+ add_named_task("autofill autocomplete username no generation", async () => {
+ await setPreferencesForTask(
+ ["signon.generation.available", false],
+ ["signon.generation.enabled", false],
+ );
+ await setStoredLoginsDuringTask([location.origin, "https://autofill", null, "user1", "pass1"]);
+
+ const form1 = setContentForTask(formTemplates.form1);
+
+ const autofillResult1 = await formAutofillResult(form1.id);
+ is(autofillResult1, "filled", "form has not been filled due to multiple logins");
+
+ // reference form was filled as expected?
+ is(form1.uname.value, "user1", "username is filled");
+ is(form1.p.value, "pass1", "password is filled");
+
+ const form2 = setContentForTask(formTemplates.form2);
+ const autofillResult2 = await formAutofillResult(form2.id);
+ is(autofillResult2, "password_autocomplete_new_password", "form has not been filled due to password_autocomplete_new_password");
+
+ // 2nd form should not be filled
+ is(form2.uname.value, "", "username is empty");
+ is(form2.password.value, "", "password is empty");
+
+ form2.uname.focus();
+ await showACPopup(2, ["user1"]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+
+ const autofillResult3 = await formAutofillResult(form2.id);
+ is(autofillResult3, "filled", "form has been filled");
+ is(form2.uname.value, "user1", "username is filled");
+ is(form2.password.value, "pass1", "password is filled");
+ });
+
+ add_named_task("autofill autocomplete password no generation", async () => {
+ await setPreferencesForTask(
+ ["signon.generation.available", false],
+ ["signon.generation.enabled", false],
+ );
+ await setStoredLoginsDuringTask([location.origin, "https://autofill", null, "user1", "pass1"]);
+
+ const form = setContentForTask(formTemplates.form2);
+ const autofillResult = await formAutofillResult(form.id);
+ is(autofillResult, "password_autocomplete_new_password", "form has not been filled due to password_autocomplete_new_password");
+
+ // form should not be filled
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, "", "password is empty");
+
+ form.password.focus();
+ // No generation option on username fields.
+ await showACPopup(2, ["user1"]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+
+ await SimpleTest.promiseWaitForCondition(() => form.password.value == "pass1", "Check pw filled");
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, "pass1", "password is filled");
+
+ // No autocomplete results should appear for non-empty pw fields.
+ await noPopupByArrowDown();
+ });
+
+ add_named_task("autofill autocomplete username no generation #2", async () => {
+ await setPreferencesForTask(
+ ["signon.generation.available", false],
+ ["signon.generation.enabled", false],
+ );
+ await setStoredLoginsDuringTask([location.origin, "https://autofill", null, "user1", "pass1"]);
+
+ const form = setContentForTask(formTemplates.form2);
+ const autofillResult1 = await formAutofillResult(form.id);
+ is(autofillResult1, "password_autocomplete_new_password", "form has not been filled due to password_autocomplete_new_password");
+
+ // form should not be filled
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, "", "password is empty");
+
+ form.uname.focus();
+ // No generation option on username fields.
+ await showACPopup(2, ["user1"]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+
+ const autofillResult2 = await formAutofillResult(form.id);
+ is(autofillResult2, "filled", "form has been filled");
+ is(form.uname.value, "user1", "username is filled");
+ is(form.password.value, "pass1", "password is filled");
+ });
+
+ add_named_task("autofill autocomplete passsword with generation", async () => {
+ await setPreferencesForTask(
+ ["signon.generation.available", true],
+ ["signon.generation.enabled", true],
+ );
+
+ runInParent(clearGeneratedPasswords);
+ await setStoredLoginsDuringTask([location.origin, "https://autofill", null, "user1", "pass1"]);
+
+ const form = setContentForTask(formTemplates.form2);
+ const formNumber = 2;
+
+ const autofillResult = await formAutofillResult(form.id);
+ is(autofillResult, "password_autocomplete_new_password", "form has not been filled due to password_autocomplete_new_password");
+
+ form.reset();
+
+ // form should not be filled
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, "", "password is empty");
+
+ form.password.focus();
+
+ await showACPopup(formNumber, [
+ "user1",
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+ await SimpleTest.promiseWaitForCondition(() => form.password.value == "pass1", "Check pw filled");
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, "pass1", "password is filled");
+
+ // No autocomplete results should appear for non-empty pw fields.
+ await noPopupByArrowDown();
+
+ info("Removing all logins to test auto-saving of generated passwords");
+ await LoginManager.removeAllUserFacingLogins();
+
+ while (form.password.value) {
+ synthesizeKey("KEY_Backspace");
+ }
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blanked field");
+
+ info("This time select the generated password");
+ await showACPopup(formNumber, [
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ const storageAddPromise = promiseStorageChanged(["addLogin"]);
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Before first fill of generated pw");
+ synthesizeKey("KEY_Enter");
+
+ info("waiting for the password field to be filled with the generated password");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check generated pw filled");
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "After first fill of generated pw");
+ info("Wait for generated password to be added to storage");
+ await storageAddPromise;
+
+ let logins = await LoginManager.getAllLogins();
+ const timePasswordChanged = logins[logins.length - 1].timePasswordChanged;
+ const time = dateAndTimeFormatter.format(new Date(timePasswordChanged));
+ const LABEL_NO_USERNAME = "No username (" + time + ")";
+
+ const generatedPW = form.password.value;
+ is(generatedPW.length, GENERATED_PASSWORD_LENGTH, "Check generated password length");
+ ok(generatedPW.match(GENERATED_PASSWORD_REGEX), "Check generated password format");
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "After fill");
+
+ info("Check field is masked upon blurring");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "After blur");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "After shift-tab to focus again");
+ // Remove selection for OS where the whole value is selected upon focus.
+ synthesizeKey("KEY_ArrowRight");
+
+ while (form.password.value) {
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, form.password.value);
+ synthesizeKey("KEY_Backspace");
+ }
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blanked field");
+
+ info("Blur the empty field to trigger a 'change' event");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blur after blanking");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Focus again after blanking");
+
+ info("Type a single character after blanking");
+ synthesizeKey("@");
+
+ info("Blur the single-character field to trigger a 'change' event");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blur after backspacing");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Focus again after backspacing");
+ synthesizeKey("KEY_Backspace"); // Blank the field again
+
+ await showACPopup(formNumber, [
+ LABEL_NO_USERNAME,
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check generated pw filled");
+ // Same generated password should be used, even despite the 'change' to @ earlier.
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, generatedPW, "password is filled with generated password");
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "Second fill of the generated pw");
+
+ logins = await LoginManager.getAllLogins();
+ is(logins.length, 1, "Still 1 login after filling the generated password a 2nd time");
+ is(logins[0].timePasswordChanged, timePasswordChanged, "Saved login wasn't changed");
+ is(logins[0].password, generatedPW, "Password is the same");
+
+ info("filling the saved login to ensure the field is masked again");
+
+ while (form.password.value) {
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, form.password.value);
+ synthesizeKey("KEY_Backspace");
+ }
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blanked field again");
+
+ info("Blur the field to trigger a 'change' event again");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blur after blanking again");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Focus again after blanking again");
+ // Remove selection for OS where the whole value is selected upon focus.
+ synthesizeKey("KEY_ArrowRight");
+
+ await showACPopup(formNumber, [
+ LABEL_NO_USERNAME,
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check saved generated pw filled");
+ // Same generated password should be used but from storage
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, generatedPW, "password is filled with generated password");
+ // Passwords from storage should always be masked.
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "after fill from storage");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "after blur");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "after shift-tab to focus again");
+ });
+
+ add_named_task("autofill autocomplete passsword with generation #2", async () => {
+ await setPreferencesForTask(
+ ["signon.generation.available", true],
+ ["signon.generation.enabled", true],
+ );
+
+ runInParent(clearGeneratedPasswords);
+ await setStoredLoginsDuringTask([location.origin, "https://autofill", null, "user1", "pass1"]);
+
+ const form = setContentForTask(formTemplates.form3);
+ const formNumber = 3;
+
+ const autofillResult = await formAutofillResult(form.id);
+ is(autofillResult, "filled", "form has been filled");
+
+ form.reset();
+
+ is(form.username.value, "", "username is empty");
+ is(form.password.value, "", "password is empty");
+
+ form.password.focus();
+
+ await showACPopup(formNumber, [
+ "user1",
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+ await SimpleTest.promiseWaitForCondition(() => form.password.value == "pass1", "Check pw filled");
+ is(form.username.value, "", "username is empty");
+ is(form.password.value, "pass1", "password is filled");
+
+ // No autocomplete results should appear for non-empty pw fields.
+ await noPopupByArrowDown();
+
+ info("Removing all logins to test auto-saving of generated passwords");
+ await LoginManager.removeAllUserFacingLogins();
+
+ while (form.password.value) {
+ synthesizeKey("KEY_Backspace");
+ }
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blanked field");
+
+ info("This time select the generated password");
+ await showACPopup(formNumber, [
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ const storageAddPromise = promiseStorageChanged(["addLogin"]);
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Before first fill of generated pw");
+ synthesizeKey("KEY_Enter");
+
+ info("waiting for the password field to be filled with the generated password");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check generated pw filled");
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "After first fill of generated pw");
+ info("Wait for generated password to be added to storage");
+ await storageAddPromise;
+
+ let logins = await LoginManager.getAllLogins();
+ const timePasswordChanged = logins[logins.length - 1].timePasswordChanged;
+ const time = dateAndTimeFormatter.format(new Date(timePasswordChanged));
+ const LABEL_NO_USERNAME = "No username (" + time + ")";
+
+ const generatedPW = form.password.value;
+ is(generatedPW.length, GENERATED_PASSWORD_LENGTH, "Check generated password length");
+ ok(generatedPW.match(GENERATED_PASSWORD_REGEX), "Check generated password format");
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "After fill");
+
+ info("Check field is masked upon blurring");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "After blur");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "After shift-tab to focus again");
+ // Remove selection for OS where the whole value is selected upon focus.
+ synthesizeKey("KEY_ArrowRight");
+
+ while (form.password.value) {
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, form.password.value);
+ synthesizeKey("KEY_Backspace");
+ }
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blanked field");
+
+ info("Blur the empty field to trigger a 'change' event");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blur after blanking");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Focus again after blanking");
+
+ info("Type a single character after blanking");
+ synthesizeKey("@");
+
+ info("Blur the single-character field to trigger a 'change' event");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blur after backspacing");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Focus again after backspacing");
+ synthesizeKey("KEY_Backspace"); // Blank the field again
+
+ await showACPopup(formNumber, [
+ LABEL_NO_USERNAME,
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check generated pw filled");
+ // Same generated password should be used, even despite the 'change' to @ earlier.
+ is(form.username.value, "", "username is empty");
+ is(form.password.value, generatedPW, "password is filled with generated password");
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, "Second fill of the generated pw");
+
+ logins = await LoginManager.getAllLogins();
+ is(logins.length, 1, "Still 1 login after filling the generated password a 2nd time");
+ is(logins[0].timePasswordChanged, timePasswordChanged, "Saved login wasn't changed");
+ is(logins[0].password, generatedPW, "Password is the same");
+
+ info("filling the saved login to ensure the field is masked again");
+
+ while (form.password.value) {
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, false, form.password.value);
+ synthesizeKey("KEY_Backspace");
+ }
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blanked field again");
+
+ info("Blur the field to trigger a 'change' event again");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Blur after blanking again");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus again
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "Focus again after blanking again");
+ // Remove selection for OS where the whole value is selected upon focus.
+ synthesizeKey("KEY_ArrowRight");
+
+ await showACPopup(formNumber, [
+ LABEL_NO_USERNAME,
+ "Use a Securely Generated Password",
+ ]);
+
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Enter");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check saved generated pw filled");
+ // Same generated password should be used but from storage
+ is(form.username.value, "", "username is empty");
+ is(form.password.value, generatedPW, "password is filled with generated password");
+ // Passwords from storage should always be masked.
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "after fill from storage");
+ synthesizeKey("KEY_Tab"); // blur
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "after blur");
+ synthesizeKey("KEY_Tab", { shiftKey: true }); // focus
+ LOGIN_FIELD_UTILS.checkPasswordMasked(form.password, true, "after shift-tab to focus again");
+ });
+
+ add_named_task("autofill autocomplete password save login disabled", async () => {
+ await setPreferencesForTask(
+ ["signon.generation.available", true],
+ ["signon.generation.enabled", true],
+ );
+ await setStoredLoginsDuringTask([location.origin, "https://autofill", null, "user1", "pass1"]);
+
+ const form = setContentForTask(formTemplates.form2);
+ const autofillResult = await formAutofillResult(form.id);
+ is(autofillResult, "password_autocomplete_new_password", "form has not been filled due to password_autocomplete_new_password");
+
+ // form should not be filled
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, "", "password is empty");
+
+ const formOrigin = new URL(document.documentURI).origin;
+ is(formOrigin, location.origin, "Expected form origin");
+
+ await LoginManager.setLoginSavingEnabled(location.origin, false);
+
+ form.password.focus();
+ // when login-saving is disabled for an origin, we expect no generated password row here
+ await showACPopup(2, ["user1"]);
+
+ // close any open menu
+ synthesizeKey("KEY_Escape");
+ await untilAutocompletePopupClosed();
+
+ await LoginManager.setLoginSavingEnabled(location.origin, true);
+ });
+
+ add_named_task("delete and reselect generated password", async () => {
+ await setPreferencesForTask(
+ ["signon.generation.available", true],
+ ["signon.generation.enabled", true],
+ );
+ await setStoredLoginsDuringTask([location.origin, "https://autofill", null, "user1", "pass1"]);
+
+ const form = setContentForTask(formTemplates.form2);
+ const autofillResult = await formAutofillResult(form.id);
+ is(autofillResult, "password_autocomplete_new_password", "form has not been filled due to password_autocomplete_new_password");
+
+ info("Removing all logins to test auto-saving of generated passwords");
+ await LoginManager.removeAllUserFacingLogins();
+
+ // form should not be filled
+ is(form.uname.value, "", "username is empty");
+ is(form.password.value, "", "password is empty");
+
+ async function showAndSelectACPopupItem(index) {
+ form.password.focus();
+ if (form.password.value) {
+ form.password.select();
+ synthesizeKey("KEY_Backspace");
+ }
+ const autocompleteItems = await popupByArrowDown();
+ if (index < 0) {
+ index = autocompleteItems.length + index;
+ }
+ for (let i = 0; i <= index; i++) {
+ synthesizeKey("KEY_ArrowDown");
+ }
+ await TestUtils.waitForTick();
+ return autocompleteItems[index];
+ }
+
+ let menuLabel, itemIndex, savedLogins;
+
+ // fill the password field with the generated password via auto-complete menu
+ const addLoginPromise = promiseStorageChanged(["addLogin"]);
+ // select last-but-2 item - the one before the footer
+ menuLabel = await showAndSelectACPopupItem(-2);
+ is(menuLabel, "Use a Securely Generated Password", "Check item label");
+ synthesizeKey("KEY_Enter");
+ info("waiting for the password field to be filled with the generated password");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check generated pw filled");
+ info("Wait for generated password to be added to storage");
+ await addLoginPromise;
+
+ savedLogins = await LoginManager.getAllLogins();
+ is(savedLogins.length, 1, "Check saved logins count");
+
+ form.uname.focus();
+ await TestUtils.waitForTick();
+
+ is(form.password.value.length, LoginTestUtils.generation.LENGTH, "Check password looks generated");
+ const GENERATED_PASSWORD = form.password.value;
+
+ info("clear the password field and delete the saved login using the AC menu")
+ const removeLoginPromise = promiseStorageChanged(["removeLogin"]);
+
+ itemIndex = 0;
+ menuLabel = await showAndSelectACPopupItem(itemIndex);
+ ok(menuLabel.includes("No username"), "Check first item is the auto-saved login");
+ // Send delete to remove the auto-saved login from storage
+ // On OS X, shift-backspace and shift-delete work, just delete does not.
+ // On Win/Linux, shift-backspace does not work, delete and shift-delete do.
+ synthesizeKey("KEY_Delete", {shiftKey: true});
+ await removeLoginPromise;
+
+ form.uname.focus();
+ await TestUtils.waitForTick();
+
+ savedLogins = await LoginManager.getAllLogins();
+ is(savedLogins.length, 0, "Check saved logins count");
+
+ info("Re-fill with the generated password");
+ // select last-but-2 item - the one before the footer
+ menuLabel = await showAndSelectACPopupItem(-2);
+ is(menuLabel, "Use a Securely Generated Password", "Check item label");
+ synthesizeKey("KEY_Enter");
+ info("waiting for the password field to be filled with the generated password");
+ await SimpleTest.promiseWaitForCondition(() => !!form.password.value, "Check generated pw filled");
+
+ form.uname.focus();
+ await TestUtils.waitForTick();
+ is(form.password.value, GENERATED_PASSWORD, "Generated password has not changed");
+ });
+</script>
+</pre>
+</body>
+</html>