summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/browser/head.js
blob: 926cb66168d57dec13223acd43251398bbbe8e73 (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
const DIRECTORY_PATH = "/browser/toolkit/components/passwordmgr/test/browser/";

Cu.import("resource://testing-common/LoginTestUtils.jsm", this);
Cu.import("resource://testing-common/ContentTaskUtils.jsm", this);

registerCleanupFunction(function* cleanup_removeAllLoginsAndResetRecipes() {
  Services.logins.removeAllLogins();

  let recipeParent = LoginTestUtils.recipes.getRecipeParent();
  if (!recipeParent) {
    // No need to reset the recipes if the recipe module wasn't even loaded.
    return;
  }
  yield recipeParent.then(recipeParentResult => recipeParentResult.reset());
});

/**
 * Loads a test page in `DIRECTORY_URL` which automatically submits to formsubmit.sjs and returns a
 * promise resolving with the field values when the optional `aTaskFn` is done.
 *
 * @param {String} aPageFile - test page file name which auto-submits to formsubmit.sjs
 * @param {Function} aTaskFn - task which can be run before the tab closes.
 * @param {String} [aOrigin="http://example.com"] - origin of the server to use
 *                                                  to load `aPageFile`.
 */
function testSubmittingLoginForm(aPageFile, aTaskFn, aOrigin = "http://example.com") {
  return BrowserTestUtils.withNewTab({
    gBrowser,
    url: aOrigin + DIRECTORY_PATH + aPageFile,
  }, function*(browser) {
    ok(true, "loaded " + aPageFile);
    let fieldValues = yield ContentTask.spawn(browser, undefined, function*() {
      yield ContentTaskUtils.waitForCondition(() => {
        return content.location.pathname.endsWith("/formsubmit.sjs") &&
          content.document.readyState == "complete";
      }, "Wait for form submission load (formsubmit.sjs)");
      let username = content.document.getElementById("user").textContent;
      let password = content.document.getElementById("pass").textContent;
      return {
        username,
        password,
      };
    });
    ok(true, "form submission loaded");
    if (aTaskFn) {
      yield* aTaskFn(fieldValues);
    }
    return fieldValues;
  });
}

function checkOnlyLoginWasUsedTwice({ justChanged }) {
  // Check to make sure we updated the timestamps and use count on the
  // existing login that was submitted for the test.
  let logins = Services.logins.getAllLogins();
  is(logins.length, 1, "Should only have 1 login");
  ok(logins[0] instanceof Ci.nsILoginMetaInfo, "metainfo QI");
  is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission");
  ok(logins[0].timeCreated < logins[0].timeLastUsed, "timeLastUsed bumped");
  if (justChanged) {
    is(logins[0].timeLastUsed, logins[0].timePasswordChanged, "timeLastUsed == timePasswordChanged");
  } else {
    is(logins[0].timeCreated, logins[0].timePasswordChanged, "timeChanged not updated");
  }
}

// Begin popup notification (doorhanger) functions //

const REMEMBER_BUTTON = 0;
const NEVER_BUTTON = 1;

const CHANGE_BUTTON = 0;
const DONT_CHANGE_BUTTON = 1;

/**
 * Checks if we have a password capture popup notification
 * of the right type and with the right label.
 *
 * @param {String} aKind The desired `passwordNotificationType`
 * @param {Object} [popupNotifications = PopupNotifications]
 * @return the found password popup notification.
 */
function getCaptureDoorhanger(aKind, popupNotifications = PopupNotifications) {
  ok(true, "Looking for " + aKind + " popup notification");
  let notification = popupNotifications.getNotification("password");
  if (notification) {
    is(notification.options.passwordNotificationType, aKind, "Notification type matches.");
    if (aKind == "password-change") {
      is(notification.mainAction.label, "Update", "Main action label matches update doorhanger.");
    } else if (aKind == "password-save") {
      is(notification.mainAction.label, "Remember", "Main action label matches save doorhanger.");
    }
  }
  return notification;
}

/**
 * Clicks the specified popup notification button.
 *
 * @param {Element} aPopup Popup Notification element
 * @param {Number} aButtonIndex Number indicating which button to click.
 *                              See the constants in this file.
 */
function clickDoorhangerButton(aPopup, aButtonIndex) {
  ok(true, "Looking for action at index " + aButtonIndex);

  let notifications = aPopup.owner.panel.childNodes;
  ok(notifications.length > 0, "at least one notification displayed");
  ok(true, notifications.length + " notification(s)");
  let notification = notifications[0];

  if (aButtonIndex == 0) {
    ok(true, "Triggering main action");
    notification.button.doCommand();
  } else if (aButtonIndex <= aPopup.secondaryActions.length) {
    ok(true, "Triggering secondary action " + aButtonIndex);
    notification.childNodes[aButtonIndex].doCommand();
  }
}

/**
 * Checks the doorhanger's username and password.
 *
 * @param {String} username The username.
 * @param {String} password The password.
 */
function* checkDoorhangerUsernamePassword(username, password) {
  yield BrowserTestUtils.waitForCondition(() => {
    return document.getElementById("password-notification-username").value == username;
  }, "Wait for nsLoginManagerPrompter writeDataToUI()");
  is(document.getElementById("password-notification-username").value, username,
     "Check doorhanger username");
  is(document.getElementById("password-notification-password").value, password,
     "Check doorhanger password");
}

// End popup notification (doorhanger) functions //