summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/browser/browser_doorhanger_promptToChangePassword.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/test/browser/browser_doorhanger_promptToChangePassword.js')
-rw-r--r--toolkit/components/passwordmgr/test/browser/browser_doorhanger_promptToChangePassword.js685
1 files changed, 685 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/browser/browser_doorhanger_promptToChangePassword.js b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_promptToChangePassword.js
new file mode 100644
index 0000000000..84c241e020
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_promptToChangePassword.js
@@ -0,0 +1,685 @@
+/**
+ * Test result of different input to the promptToChangePassword doorhanger
+ */
+
+"use strict";
+
+// The origin for the test URIs.
+const TEST_ORIGIN = "https://example.com";
+const passwordInputSelector = "#form-basic-password";
+const usernameInputSelector = "#form-basic-username";
+
+const availLoginsByValue = new Map();
+let savedLoginsByName;
+const finalLoginsByGuid = new Map();
+let finalLogins;
+
+const availLogins = {
+ emptyXYZ: LoginTestUtils.testData.formLogin({
+ username: "",
+ password: "xyz",
+ }),
+ bobXYZ: LoginTestUtils.testData.formLogin({
+ username: "bob",
+ password: "xyz",
+ }),
+ bobABC: LoginTestUtils.testData.formLogin({
+ username: "bob",
+ password: "abc",
+ }),
+};
+availLoginsByValue.set(availLogins.emptyXYZ, "emptyXYZ");
+availLoginsByValue.set(availLogins.bobXYZ, "bobXYZ");
+availLoginsByValue.set(availLogins.bobABC, "bobABC");
+
+async function showChangePasswordDoorhanger(
+ browser,
+ oldLogin,
+ formLogin,
+ { notificationType = "password-change", autoSavedLoginGuid = "" } = {}
+) {
+ let windowGlobal = browser.browsingContext.currentWindowGlobal;
+ let loginManagerActor = windowGlobal.getActor("LoginManager");
+ let prompter = loginManagerActor._getPrompter(browser, null);
+ Assert.ok(
+ !PopupNotifications.isPanelOpen,
+ "Check the doorhanger isn't already open"
+ );
+
+ let promiseShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ prompter.promptToChangePassword(
+ browser,
+ oldLogin,
+ formLogin,
+ false, // dimissed prompt
+ false, // notifySaved
+ autoSavedLoginGuid
+ );
+ await promiseShown;
+
+ let notif = getCaptureDoorhanger(notificationType);
+ Assert.ok(notif, `${notificationType} notification exists`);
+
+ let { panel } = PopupNotifications;
+ let notificationElement = panel.childNodes[0];
+ await BrowserTestUtils.waitForCondition(() => {
+ return (
+ notificationElement.querySelector("#password-notification-password")
+ .value == formLogin.password &&
+ notificationElement.querySelector("#password-notification-username")
+ .value == formLogin.username
+ );
+ }, "Wait for the notification panel to be populated");
+ return notif;
+}
+
+async function setupLogins(...logins) {
+ Services.logins.removeAllUserFacingLogins();
+ let savedLogins = {};
+ let timesCreated = new Set();
+ for (let login of logins) {
+ let loginName = availLoginsByValue.get(login);
+ let savedLogin = await LoginTestUtils.addLogin(login);
+ // we rely on sorting by timeCreated so ensure none are identical
+ Assert.ok(
+ !timesCreated.has(savedLogin.timeCreated),
+ "Each login has a different timeCreated"
+ );
+ timesCreated.add(savedLogin.timeCreated);
+ savedLogins[loginName || savedLogin.guid] = savedLogin.clone();
+ }
+ return savedLogins;
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["signon.autofillForms", false]],
+ });
+ Assert.ok(!PopupNotifications.isPanelOpen, "No notifications panel open");
+});
+
+async function promptToChangePasswordTest(testData) {
+ info("Starting: " + testData.name);
+ savedLoginsByName = await setupLogins(...testData.initialSavedLogins);
+ await SimpleTest.promiseFocus();
+ info("got focus");
+
+ let oldLogin = savedLoginsByName[testData.promptArgs.oldLogin];
+ let changeLogin = LoginTestUtils.testData.formLogin(
+ testData.promptArgs.changeLogin
+ );
+ let options;
+ if (testData.autoSavedLoginName) {
+ options = {
+ autoSavedLoginGuid: savedLoginsByName[testData.autoSavedLoginName].guid,
+ };
+ }
+ info(
+ "Waiting for showChangePasswordDoorhanger, username: " +
+ changeLogin.username
+ );
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ TEST_ORIGIN,
+ },
+ async function (browser) {
+ await SimpleTest.promiseFocus(browser.ownerGlobal);
+ let notif = await showChangePasswordDoorhanger(
+ browser,
+ oldLogin,
+ changeLogin,
+ options
+ );
+
+ await updateDoorhangerInputValues(testData.promptTextboxValues);
+
+ let mainActionButton = getDoorhangerButton(notif, CHANGE_BUTTON);
+ Assert.equal(
+ mainActionButton.label,
+ testData.expectedButtonLabel,
+ "Check button label"
+ );
+
+ let { panel } = PopupNotifications;
+ let promiseHidden = BrowserTestUtils.waitForEvent(panel, "popuphidden");
+ let storagePromise;
+ if (testData.expectedStorageChange) {
+ storagePromise = TestUtils.topicObserved("passwordmgr-storage-changed");
+ }
+
+ info("Clicking mainActionButton");
+ mainActionButton.doCommand();
+ info("Waiting for promiseHidden");
+ await promiseHidden;
+ info("Waiting for storagePromise");
+ await storagePromise;
+
+ // ensure the notification was removed to keep clean state for next run
+ await cleanupDoorhanger(notif);
+
+ info(testData.resultDescription);
+
+ finalLoginsByGuid.clear();
+ finalLogins = Services.logins.getAllLogins();
+ finalLogins.sort((a, b) => a.timeCreated > b.timeCreated);
+
+ for (let l of finalLogins) {
+ info(`saved login: ${l.guid}: ${l.username}/${l.password}`);
+ finalLoginsByGuid.set(l.guid, l);
+ }
+ info("verifyLogins next");
+ verifyLogins(testData.expectedResultLogins);
+ if (testData.resultCheck) {
+ testData.resultCheck();
+ }
+ }
+ );
+}
+
+let tests = [
+ {
+ name: "Add username to sole login",
+ initialSavedLogins: [availLogins.emptyXYZ],
+ promptArgs: {
+ oldLogin: "emptyXYZ",
+ changeLogin: {
+ username: "zaphod",
+ password: "xyz",
+ },
+ },
+ promptTextboxValues: {},
+ expectedButtonLabel: "Update",
+ resultDescription: "The existing login just gets a new password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "zaphod",
+ password: "xyz",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.emptyXYZ.guid,
+ "Check guid"
+ );
+ },
+ },
+ {
+ name: "Change password of the sole login",
+ initialSavedLogins: [availLogins.bobXYZ],
+ promptArgs: {
+ oldLogin: "bobXYZ",
+ changeLogin: {
+ username: "bob",
+ password: "&*$",
+ },
+ },
+ promptTextboxValues: {},
+ expectedButtonLabel: "Update",
+ resultDescription: "The existing login just gets a new password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "bob",
+ password: "&*$",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.bobXYZ.guid,
+ "Check guid"
+ );
+ },
+ },
+ {
+ name: "Change password of the sole empty-username login",
+ initialSavedLogins: [availLogins.emptyXYZ],
+ promptArgs: {
+ oldLogin: "emptyXYZ",
+ changeLogin: {
+ username: "",
+ password: "&*$",
+ },
+ },
+ promptTextboxValues: {},
+ expectedButtonLabel: "Update",
+ resultDescription: "The existing login just gets a new password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "",
+ password: "&*$",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.emptyXYZ.guid,
+ "Check guid"
+ );
+ },
+ },
+ {
+ name: "Add different username to empty-usernamed login",
+ initialSavedLogins: [availLogins.emptyXYZ, availLogins.bobABC],
+ promptArgs: {
+ oldLogin: "emptyXYZ",
+ changeLogin: {
+ username: "alice",
+ password: "xyz",
+ },
+ },
+ promptTextboxValues: {},
+ expectedButtonLabel: "Update",
+ resultDescription: "The existing login just gets a new username",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "alice",
+ password: "xyz",
+ },
+ {
+ username: "bob",
+ password: "abc",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.emptyXYZ.guid,
+ "Check guid"
+ );
+ Assert.ok(
+ finalLogins[0].timeLastUsed > savedLoginsByName.emptyXYZ.timeLastUsed,
+ "Check timeLastUsed of 0th login"
+ );
+ },
+ },
+ {
+ name: "Add username to autosaved login to match an existing usernamed login",
+ initialSavedLogins: [availLogins.emptyXYZ, availLogins.bobABC],
+ autoSavedLoginName: "emptyXYZ",
+ promptArgs: {
+ oldLogin: "emptyXYZ",
+ changeLogin: {
+ username: "bob",
+ password: availLogins.emptyXYZ.password,
+ },
+ },
+ promptTextboxValues: {},
+ expectedButtonLabel: "Update",
+ resultDescription:
+ "Empty-username login is removed, other login gets the empty-login's password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "bob",
+ password: "xyz",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.ok(
+ finalLogins[0].timeLastUsed > savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed changed"
+ );
+ },
+ },
+ {
+ name: "Add username to non-autosaved login to match an existing usernamed login",
+ initialSavedLogins: [availLogins.emptyXYZ, availLogins.bobABC],
+ autoSavedLoginName: "",
+ promptArgs: {
+ oldLogin: "emptyXYZ",
+ changeLogin: {
+ username: "bob",
+ password: availLogins.emptyXYZ.password,
+ },
+ },
+ promptTextboxValues: {},
+ expectedButtonLabel: "Update",
+ // We can't end up with duplicates (bob:xyz and bob:ABC) so the following seems reasonable.
+ // We could delete the emptyXYZ but we would want to intelligently merge metadata.
+ resultDescription:
+ "Multiple login matches but user indicated they want bob:xyz in the prompt so modify bob to give that",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "",
+ password: "xyz",
+ },
+ {
+ username: "bob",
+ password: "xyz",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.emptyXYZ.guid,
+ "Check guid"
+ );
+ Assert.equal(
+ finalLogins[0].timeLastUsed,
+ savedLoginsByName.emptyXYZ.timeLastUsed,
+ "Check timeLastUsed didn't change"
+ );
+ Assert.equal(
+ finalLogins[0].timePasswordChanged,
+ savedLoginsByName.emptyXYZ.timePasswordChanged,
+ "Check timePasswordChanged didn't change"
+ );
+
+ Assert.equal(
+ finalLogins[1].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.ok(
+ finalLogins[1].timeLastUsed > savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed did change"
+ );
+ Assert.ok(
+ finalLogins[1].timePasswordChanged >
+ savedLoginsByName.bobABC.timePasswordChanged,
+ "Check timePasswordChanged did change"
+ );
+ },
+ },
+ {
+ name: "Username & password changes to an auto-saved login apply to matching usernamed-login",
+ // when we update an auto-saved login - changing both username & password, is
+ // the matching login updated and empty-username login removed?
+ initialSavedLogins: [availLogins.emptyXYZ, availLogins.bobABC],
+ autoSavedLoginName: "emptyXYZ",
+ promptArgs: {
+ oldLogin: "emptyXYZ",
+ changeLogin: {
+ username: "bob",
+ password: "xyz",
+ },
+ },
+ promptTextboxValues: {
+ // type a new password in the doorhanger
+ password: "newpassword",
+ },
+ expectedButtonLabel: "Update",
+ resultDescription:
+ "The empty-username login is removed, other login gets the new password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "bob",
+ password: "newpassword",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.ok(
+ finalLogins[0].timeLastUsed > savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed did change"
+ );
+ },
+ },
+ {
+ name: "Username & password changes to a non-auto-saved login matching usernamed-login",
+ // when we update a non-auto-saved login - changing both username & password, is
+ // the matching login updated and empty-username login unchanged?
+ initialSavedLogins: [availLogins.emptyXYZ, availLogins.bobABC],
+ autoSavedLoginName: "", // no auto-saved logins for this session
+ promptArgs: {
+ oldLogin: "emptyXYZ",
+ changeLogin: {
+ username: "bob",
+ password: "xyz",
+ },
+ },
+ promptTextboxValues: {
+ // type a new password in the doorhanger
+ password: "newpassword",
+ },
+ expectedButtonLabel: "Update",
+ resultDescription:
+ "The empty-username login is not changed, other login gets the new password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "",
+ password: "xyz",
+ },
+ {
+ username: "bob",
+ password: "newpassword",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.emptyXYZ.guid,
+ "Check guid"
+ );
+ Assert.equal(
+ finalLogins[0].timeLastUsed,
+ savedLoginsByName.emptyXYZ.timeLastUsed,
+ "Check timeLastUsed didn't change"
+ );
+ Assert.equal(
+ finalLogins[0].timePasswordChanged,
+ savedLoginsByName.emptyXYZ.timePasswordChanged,
+ "Check timePasswordChanged didn't change"
+ );
+ Assert.equal(
+ finalLogins[1].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.ok(
+ finalLogins[1].timeLastUsed > savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed did change"
+ );
+ Assert.ok(
+ finalLogins[1].timePasswordChanged >
+ savedLoginsByName.bobABC.timePasswordChanged,
+ "Check timePasswordChanged did change"
+ );
+ },
+ },
+ {
+ name: "Remove the username and change password of autosaved login",
+ initialSavedLogins: [availLogins.bobABC],
+ autoSavedLoginName: "bobABC",
+ promptArgs: {
+ oldLogin: "bobABC",
+ changeLogin: {
+ username: "bob",
+ password: "abc!", // trigger change prompt with a password change
+ },
+ },
+ promptTextboxValues: {
+ username: "",
+ },
+ expectedButtonLabel: "Update",
+ resultDescription:
+ "The auto-saved login is updated with new empty-username login and new password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "",
+ password: "abc!",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.ok(
+ finalLogins[0].timeLastUsed > savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed did change"
+ );
+ Assert.ok(
+ finalLogins[0].timePasswordChanged >
+ savedLoginsByName.bobABC.timePasswordChanged,
+ "Check timePasswordChanged did change"
+ );
+ },
+ },
+ {
+ name: "Remove the username and change password of non-autosaved login",
+ initialSavedLogins: [availLogins.bobABC],
+ // no autosaved guid
+ promptArgs: {
+ oldLogin: "bobABC",
+ changeLogin: {
+ username: "bob",
+ password: "abc!", // trigger change prompt with a password change
+ },
+ },
+ promptTextboxValues: {
+ username: "",
+ },
+ expectedButtonLabel: "Save",
+ resultDescription:
+ "A new empty-username login is created with the new password",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "bob",
+ password: "abc",
+ },
+ {
+ username: "",
+ password: "abc!",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.equal(
+ finalLogins[0].timeLastUsed,
+ savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed didn't change"
+ );
+ Assert.equal(
+ finalLogins[0].timePasswordChanged,
+ savedLoginsByName.bobABC.timePasswordChanged,
+ "Check timePasswordChanged didn't change"
+ );
+ },
+ },
+ {
+ name: "Remove username from the auto-saved sole login",
+ initialSavedLogins: [availLogins.bobABC],
+ autoSavedLoginName: "bobABC",
+ promptArgs: {
+ oldLogin: "bobABC",
+ changeLogin: {
+ username: "bob",
+ password: "abc!", // trigger change prompt with a password change
+ },
+ },
+ promptTextboxValues: {
+ username: "",
+ password: "abc", // put password back to what it was
+ },
+ expectedButtonLabel: "Update",
+ resultDescription: "The existing login is updated",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "",
+ password: "abc",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.ok(
+ finalLogins[0].timeLastUsed > savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed did change"
+ );
+ todo_is(
+ finalLogins[0].timePasswordChanged,
+ savedLoginsByName.bobABC.timePasswordChanged,
+ "Check timePasswordChanged didn't change"
+ );
+ },
+ },
+ {
+ name: "Remove username from the non-auto-saved sole login",
+ initialSavedLogins: [availLogins.bobABC],
+ // no autoSavedLoginGuid
+ promptArgs: {
+ oldLogin: "bobABC",
+ changeLogin: {
+ username: "bob",
+ password: "abc!", // trigger change prompt with a password change
+ },
+ },
+ promptTextboxValues: {
+ username: "",
+ password: "abc", // put password back to what it was
+ },
+ expectedButtonLabel: "Save",
+ resultDescription: "A new empty-username login is created",
+ expectedStorageChange: true,
+ expectedResultLogins: [
+ {
+ username: "bob",
+ password: "abc",
+ },
+ {
+ username: "",
+ password: "abc",
+ },
+ ],
+ resultCheck() {
+ Assert.equal(
+ finalLogins[0].guid,
+ savedLoginsByName.bobABC.guid,
+ "Check guid"
+ );
+ Assert.equal(
+ finalLogins[0].timeLastUsed,
+ savedLoginsByName.bobABC.timeLastUsed,
+ "Check timeLastUsed didn't change"
+ );
+ Assert.equal(
+ finalLogins[0].timePasswordChanged,
+ savedLoginsByName.bobABC.timePasswordChanged,
+ "Check timePasswordChanged didn't change"
+ );
+ },
+ },
+];
+
+for (let testData of tests) {
+ let tmp = {
+ async [testData.name]() {
+ await promptToChangePasswordTest(testData);
+ },
+ };
+ add_task(tmp[testData.name]);
+}