summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/browser/browser_notifications_password.js
blob: 8ac49dac55f0c427fd148c38feb4a7ff9d8d78d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * Test changing the password inside the doorhanger notification for passwords.
 *
 * We check the following cases:
 *   - Editing the password of a new login.
 *   - Editing the password of an existing login.
 *   - Changing both username and password to an existing login.
 *   - Changing the username to an existing login.
 *   - Editing username to an empty one and a new password.
 *
 * If both the username and password matches an already existing login, we should not
 * update it's password, but only it's usage timestamp and count.
 */
add_task(function* test_edit_password() {
  let testCases = [{
    usernameInPage: "username",
    passwordInPage: "password",
    passwordChangedTo: "newPassword",
    timesUsed: 1,
  }, {
    usernameInPage: "username",
    usernameInPageExists: true,
    passwordInPage: "password",
    passwordInStorage: "oldPassword",
    passwordChangedTo: "newPassword",
    timesUsed: 2,
  }, {
    usernameInPage: "username",
    usernameChangedTo: "newUsername",
    usernameChangedToExists: true,
    passwordInPage: "password",
    passwordChangedTo: "newPassword",
    timesUsed: 2,
  }, {
    usernameInPage: "username",
    usernameChangedTo: "newUsername",
    usernameChangedToExists: true,
    passwordInPage: "password",
    passwordChangedTo: "password",
    timesUsed: 2,
    checkPasswordNotUpdated: true,
  }, {
    usernameInPage: "newUsername",
    usernameChangedTo: "",
    usernameChangedToExists: true,
    passwordInPage: "password",
    passwordChangedTo: "newPassword",
    timesUsed: 2,
  }];

  for (let testCase of testCases) {
    info("Test case: " + JSON.stringify(testCase));

    // Create the pre-existing logins when needed.
    if (testCase.usernameInPageExists) {
      Services.logins.addLogin(LoginTestUtils.testData.formLogin({
        hostname: "https://example.com",
        formSubmitURL: "https://example.com",
        username: testCase.usernameInPage,
        password: testCase.passwordInStorage,
      }));
    }

    if (testCase.usernameChangedToExists) {
      Services.logins.addLogin(LoginTestUtils.testData.formLogin({
        hostname: "https://example.com",
        formSubmitURL: "https://example.com",
        username: testCase.usernameChangedTo,
        password: testCase.passwordChangedTo,
      }));
    }

    yield BrowserTestUtils.withNewTab({
      gBrowser,
      url: "https://example.com/browser/toolkit/components/" +
           "passwordmgr/test/browser/form_basic.html",
    }, function* (browser) {
      // Submit the form in the content page with the credentials from the test
      // case. This will cause the doorhanger notification to be displayed.
      let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
                                                       "popupshown",
                                                       (event) => event.target == PopupNotifications.panel);
      yield ContentTask.spawn(browser, testCase,
        function* (contentTestCase) {
          let doc = content.document;
          doc.getElementById("form-basic-username").value = contentTestCase.usernameInPage;
          doc.getElementById("form-basic-password").value = contentTestCase.passwordInPage;
          doc.getElementById("form-basic").submit();
        });
      yield promiseShown;
      let notificationElement = PopupNotifications.panel.childNodes[0];
      // Style flush to make sure binding is attached
      notificationElement.querySelector("#password-notification-password").clientTop;

      // Modify the username in the dialog if requested.
      if (testCase.usernameChangedTo) {
        notificationElement.querySelector("#password-notification-username")
                .value = testCase.usernameChangedTo;
      }

      // Modify the password in the dialog if requested.
      if (testCase.passwordChangedTo) {
        notificationElement.querySelector("#password-notification-password")
                .value = testCase.passwordChangedTo;
      }

      // We expect a modifyLogin notification if the final username used by the
      // dialog exists in the logins database, otherwise an addLogin one.
      let expectModifyLogin = typeof testCase.usernameChangedTo !== "undefined"
                              ? testCase.usernameChangedToExists
                              : testCase.usernameInPageExists;

      // Simulate the action on the notification to request the login to be
      // saved, and wait for the data to be updated or saved based on the type
      // of operation we expect.
      let expectedNotification = expectModifyLogin ? "modifyLogin" : "addLogin";
      let promiseLogin = TestUtils.topicObserved("passwordmgr-storage-changed",
                         (_, data) => data == expectedNotification);
      notificationElement.button.doCommand();
      let [result] = yield promiseLogin;

      // Check that the values in the database match the expected values.
      let login = expectModifyLogin ? result.QueryInterface(Ci.nsIArray)
                                            .queryElementAt(1, Ci.nsILoginInfo)
                                    : result.QueryInterface(Ci.nsILoginInfo);

      Assert.equal(login.username, testCase.usernameChangedTo ||
                                   testCase.usernameInPage);
      Assert.equal(login.password, testCase.passwordChangedTo ||
                                   testCase.passwordInPage);

      let meta = login.QueryInterface(Ci.nsILoginMetaInfo);
      Assert.equal(meta.timesUsed, testCase.timesUsed);

      // Check that the password was not updated if the user is empty
      if (testCase.checkPasswordNotUpdated) {
        Assert.ok(meta.timeLastUsed > meta.timeCreated);
        Assert.ok(meta.timeCreated == meta.timePasswordChanged);
      }
    });

    // Clean up the database before the next test case is executed.
    Services.logins.removeAllLogins();
  }
});