Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'android' OR os == 'android'
- Manifest: toolkit/components/passwordmgr/test/mochitest/mochitest.toml
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test filling generated passwords into confirm 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: filling generated passwords into confirm password fields
<template id="form1-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="pwordNext">
<button type="submit">Submit</button>
</form>
</template>
<template id="form2-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="pwordNext" value="initial value">
<button type="submit">Submit</button>
</form>
</template>
<template id="form3-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="pwordNext" readonly>
<button type="submit">Submit</button>
</form>
</template>
<template id="form4-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="pwordNext" disabled>
<button type="submit">Submit</button>
</form>
</template>
<template id="form5-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="pwordBetween">
<input type="password" name="pwordNext" autocomplete="new-password">
<button type="submit">Submit</button>
</form>
</template>
<template id="form6-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="pwordNext">
<input type="password" name="pwordAfter" autocomplete="new-password" disabled>
<button type="submit">Submit</button>
</form>
</template>
<template id="form7-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="junk0">
<input type="password" name="junk1">
<input type="password" name="junk2">
<input type="password" name="junk3">
<input type="password" name="junk4">
<input type="password" name="pwordNext" autocomplete="new-password">
<button type="submit">Submit</button>
</form>
</template>
<template id="form8-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="junk0" disabled>
<input type="password" name="junk1" disabled>
<input type="password" name="junk2" disabled>
<input type="password" name="junk3" disabled>
<input type="password" name="junk4" disabled>
<input type="password" name="pwordNext" autocomplete="new-password">
<button type="submit">Submit</button>
</form>
</template>
<template id="form9-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="hidden" name="junk0">
<input type="hidden" name="junk1">
<input type="hidden" name="junk2">
<input type="hidden" name="junk3">
<input type="hidden" name="junk4">
<input type="password" name="pwordNext" autocomplete="new-password">
<button type="submit">Submit</button>
</form>
</template>
<template id="form10-template">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="new-password">
<input type="password" name="pwordNext" autocomplete="new-password">
<input type="password" name="pwordExtra" autocomplete="new-password">
<button type="submit">Submit</button>
</form>
</template>
<script class="testbody" type="text/javascript">
const formTemplates = {
form1: document.getElementById("form1-template"),
form2: document.getElementById("form2-template"),
form3: document.getElementById("form3-template"),
form4: document.getElementById("form4-template"),
form5: document.getElementById("form5-template"),
form6: document.getElementById("form6-template"),
form7: document.getElementById("form7-template"),
form8: document.getElementById("form8-template"),
form9: document.getElementById("form9-template"),
form10: document.getElementById("form10-template"),
};
const setupScript = runInParent(function parentTestSetup() {
const { LoginTestUtils } = ChromeUtils.importESModule(
);
addMessageListener(
"resetLoginsAndGeneratedPasswords", () => {
LoginTestUtils.clearData();
LoginTestUtils.resetGeneratedPasswordsCache();
return Promise.resolve();
}
);
});
function resetLoginsAndGeneratedPasswords() {
return setupScript.sendQuery("resetLoginsAndGeneratedPasswords");
}
async function triggerPasswordGeneration(form) {
await openPopupOn(form.pword);
synthesizeKey("KEY_ArrowDown");
synthesizeKey("KEY_Enter");
const storageAddPromise = promiseStorageChanged(["addLogin"]);
await SimpleTest.promiseWaitForCondition(() => !!form.pword.value, "Wait for generated password to get filled");
await storageAddPromise;
}
add_setup(async () => {
SpecialPowers.pushPrefEnv({"set": [["signon.webauthn.autocomplete", false]]});
})
add_named_task("autocomplete menu contains option to generate password", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
const { items } = await openPopupOn(form.pword);
checkAutoCompleteResults(items, [
"Use a Securely Generated Password"
], location.host, "Check all rows are correct");
});
add_named_task("username field highlight", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
ok(!form.uname.matches(":autofill"), "Highlight was not applied to the username field");
});
add_named_task("password field highlight", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
ok(form.pword.matches(":autofill"), "Highlight was applied to the password field");
});
add_named_task("username field is left untouched", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
is(form.uname.value, "", "Value is still empty")
});
add_named_task("generated password looks like a generated password", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
const generatedPassword = form.pword.value;
is(generatedPassword.length, GENERATED_PASSWORD_LENGTH, "Generated password length matches");
ok(generatedPassword.match(GENERATED_PASSWORD_REGEX), "Generated password format matches");
});
add_named_task("password confirmation also gets filled with the generated password", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
await SimpleTest.promiseWaitForCondition(() => form.pword.value == form.pwordNext.value, "Value of the confirm field has been filled with generated password");
});
add_named_task("password field is not masked initially after password generation", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, false, "password field is not masked after password generation");
LOGIN_FIELD_UTILS.checkPasswordMasked(form.pwordNext, true, "password confirmation field is masked after user input");
});
add_named_task("password field is masked after user input", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
form.pwordNext.focus();
form.pwordNext.select();
synthesizeKey("KEY_Backspace");
synthesizeKey("a");
form.pwordNext.blur();
LOGIN_FIELD_UTILS.checkPasswordMasked(form.pword, true, "password field is masked after user input");
LOGIN_FIELD_UTILS.checkPasswordMasked(form.pwordNext, true, "password confirmation field is also masked after user input");
});
add_named_task("password field highlight is cleared after user input", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
form.pwordNext.focus();
form.pwordNext.select();
synthesizeKey("KEY_Backspace");
synthesizeKey("a");
form.pwordNext.blur();
await SimpleTest.promiseWaitForCondition(() => !form.pwordNext.matches(":autofill"), "Highlight was cleared");
});
add_named_task("generated password can be changed", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
const generatedPassword = form.pword.value;
form.pword.focus();
synthesizeKey("KEY_End");
synthesizeKey("@");
is(form.pword.value, `${generatedPassword}@`, "Value of the password field changed");
});
add_named_task("password confirmation field does not receive changes from password field", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
const generatedPassword = form.pword.value;
// changing the password field value should result in a message sent to the parent process
const messageSentPromise = getPasswordEditedMessage();
form.pword.focus();
synthesizeKey("KEY_End");
synthesizeKey("@");
// bluring results in a "change" event
form.pword.blur();
await messageSentPromise;
await SimpleTest.promiseWaitForCondition(() => form.pwordNext.value == generatedPassword, "Value of the confirm field still holds the original generated password");
ok(form.pwordNext.matches(":autofill"), "Highlight is still applied to password confirmation field");
});
add_named_task("password confirmation field behaves like a normal password field once changed", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
await triggerPasswordGeneration(form);
form.pwordNext.focus();
form.pwordNext.select();
synthesizeKey("KEY_Backspace");
// verify the focused confirm field now masks its input like a normal,
// non-generated password field after being emptied
form.pwordNext.focus();
synthesizeKey("a");
form.pwordNext.blur();
LOGIN_FIELD_UTILS.checkPasswordMasked(form.pwordNext, true, "password confirmation field is masked");
await SimpleTest.promiseWaitForCondition(() => !form.pwordNext.matches(":autofill"), "highlight was cleared");
});
add_named_task("password confirmation also gets filled with the generated password, even if it has been changed to be of type text", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
form.pwordNext.type = "text";
await triggerPasswordGeneration(form);
is(form.pwordNext.value, form.pword.value, "Value of the confirm field has been filled with generated password");
});
add_named_task("password confirmation does not get filled with the generated password if it is not empty", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form2);
await triggerPasswordGeneration(form);
is(form.pwordNext.value, "initial value", "Value of the confirm field has been filled with generated password");
});
add_named_task("password confirmation does not get filled with the generated password if it has been edited", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form1);
form.pwordNext.focus()
sendString("edited value");
await triggerPasswordGeneration(form);
await SimpleTest.promiseWaitForCondition(() => form.pwordNext.value == "edited value", "Value of the confirm field has been filled with generated password");
});
add_named_task("password confirmation does not get filled with the generated password if its readonly", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form3);
await triggerPasswordGeneration(form);
await SimpleTest.promiseWaitForCondition(() => form.pwordNext.value == "", "Value of the confirm field has been filled with generated password");
});
add_named_task("password confirmation does not get filled with the generated password if its disabled", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form4);
await triggerPasswordGeneration(form);
await SimpleTest.promiseWaitForCondition(() => form.pwordNext.value == "", "Value of the confirm field has been filled with generated password");
});
add_named_task("password confirmation matching autocomplete info gets filled with the generated password", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form5);
await triggerPasswordGeneration(form);
is(form.pwordBetween.value, "", "Value of the between field has not been filled");
await SimpleTest.promiseWaitForCondition(() => form.pwordNext.value == form.pword.value, "Value of the confirm field has been filled with generated password");
});
add_named_task("password confirmation matching autocomplete info gets ignored if its disabled, even if has autocomplete info", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form6);
await triggerPasswordGeneration(form);
await SimpleTest.promiseWaitForCondition(() => form.pwordNext.value == form.pword.value, "Value of the confirm field has been filled with generated password");
is(form.pwordAfter.value, "", "Value of the disabled confirmation field has not been filled");
});
add_named_task("password confirmation matching autocomplete info gets ignored there are too many fields in between, even if has autocomplete info", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form7);
await triggerPasswordGeneration(form);
is(form.pwordNext.value, "", "Value of the confirm field has not been filled");
});
add_named_task("password confirmation matching autocomplete info gets ignored there are too many disabled fields in between, even if has autocomplete info", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form8);
await triggerPasswordGeneration(form);
is(form.pwordNext.value, "", "Value of the confirm field has not been filled");
});
add_named_task("password confirmation matching autocomplete info gets filled even if there are many hidden fields in between", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form9);
await triggerPasswordGeneration(form);
await SimpleTest.promiseWaitForCondition(() => form.pwordNext.value == form.pword.value, "Value of the confirm field has been filled with generated password");
});
add_named_task("do not fill third password field after the confirm-password field", async () => {
await resetLoginsAndGeneratedPasswords();
const form = setContentForTask(formTemplates.form10);
await triggerPasswordGeneration(form);
is(form.pwordExtra.value, "", "Value of the additional confirm field has not been filled");
});
</script>
</pre>
</body>
</html>