toolkit/components/passwordmgr/test/test_notifications.html
author Bernardo P. Rittmeyer <bernardo@rittme.com>
Wed, 16 Sep 2015 01:04:00 +0200
changeset 295246 105633f695fae3769f9c72832c8b1d19a5941c97
parent 284027 bffb6366654aee5d617d01682943d293f232cc94
child 326160 28bca8e29596cfa1c24b864925cb5cb5e20e35ab
permissions -rw-r--r--
Bug 1016051 - Support adding a username to a password-only login upon capture. r=MattN

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Test for Login Manager</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="pwmgr_common.js"></script>
  <script type="text/javascript" src="notification_common.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Login Manager test: notifications
<p id="display"></p>

<div id="content" style="display: none">
  <iframe id="iframe"></iframe>
</div>

<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">

/** Test for Login Manager: notifications. **/

const { Services } = SpecialPowers.Cu.import("resource://gre/modules/Services.jsm");

const BRAND_BUNDLE = "chrome://branding/locale/brand.properties";

// Set testpath to the directory where we live. Used to load tests from
// alternate Mochitest servers (different hostnames, same content).
var testpath = document.location.pathname + "/../";

var subtests = [
                   "subtst_notifications_1.html", // 1
                   "subtst_notifications_1.html", // 2
                   "subtst_notifications_1.html", // 3
                   "subtst_notifications_1.html", // 4
                   "subtst_notifications_1.html", // 5
                   "subtst_notifications_1.html", // 6
                   "subtst_notifications_1.html", // 7
                   "subtst_notifications_1.html", // 8
                   "subtst_notifications_2.html", // 9
                   "subtst_notifications_3.html", // 10
                   "subtst_notifications_4.html", // 11
                   "subtst_notifications_5.html", // 12
                   "subtst_notifications_1.html", // 13
                   "subtst_notifications_6.html", // 14
                   "subtst_notifications_1.html", // 15
                   "subtst_notifications_6.html", // 16
                   "subtst_notifications_8.html", // 17
                   "subtst_notifications_8.html", // 18
                   "subtst_notifications_9.html", // 19
                   "subtst_notifications_10.html",  // 20
                   "http://test1.example.org:80" + testpath + "subtst_notifications_1.html", // 21
                   "http://test1.example.org:80" + testpath + "subtst_notifications_7.html", // 22
                   "http://test1.example.org:80" + testpath + "subtst_notifications_6.html", // 23
                   "subtst_notifications_2pw_0un.html",  // 24
                   "subtst_notifications_2pw_0un.html",  // 25
                   "subtst_notifications_2pw_0un.html",  // 26
                   "subtst_notifications_2pw_0un.html",  // 27
                   "subtst_notifications_2pw_0un.html",  // 28
                   "http://example.org" + testpath + "subtst_notifications_2pw_1un_1text.html", // 29
                   "http://example.org" + testpath + "subtst_notifications_2pw_1un_1text.html", // 30
                   "subtst_notifications_1.html", // 31
               ];


var ignoreLoad = false;
function handleLoad(aEvent) {
    // ignore every other load event ... We get one for loading the subtest (which
    // we want to ignore), and another when the subtest's form submits itself
    // (which we want to handle, to start the next test).
    ignoreLoad = !ignoreLoad;
    if (ignoreLoad) {
        ok(true, "Ignoring load of subtest #" + testNum);
        return;
    }
    ok(true, "Processing submission of subtest #" + testNum);

    checkTest();

    testNum++;

    if (testNum <= subtests.length) {
        ok(true, "Starting test #" + testNum);
        iframe.src = subtests[testNum-1];
    } else {
        ok(true, "notification tests finished.");
        SimpleTest.finish();
    }
}


// Remember, Never for This Site, Not Now
function checkTest() {
    var popup, notificationText, expectedText;

    // The document generated from formsubmit.sjs contains the user/pass it
    // received inside <span id="blah">value</span>
    var gotUser = SpecialPowers.wrap(iframe).contentDocument.getElementById("user").textContent;
    var gotPass = SpecialPowers.wrap(iframe).contentDocument.getElementById("pass").textContent;

    let brandBundle = Services.strings.createBundle(BRAND_BUNDLE);
    let brandShortName = brandBundle.GetStringFromName("brandShortName");

    switch(testNum) {

      /* Basic Yes/No/Never tests... */

      case 1:
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        popup.remove();
        break;

      case 2:
        // Same subtest, this time click Never
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        is(true, pwmgr.getLoginSavingEnabled("http://mochi.test:8888"),
           "Checking for login saving enabled");
        clickPopupButton(popup, kNeverButton);
        break;

      case 3:
        // Same subtest, make sure Never took effect
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(!popup, "checking for no notification popup");
        is(false, pwmgr.getLoginSavingEnabled("http://mochi.test:8888"),
           "Checking for login saving disabled");
        // reenable login saving.
        pwmgr.setLoginSavingEnabled("http://mochi.test:8888", true);
        break;

      case 4:
        // Same subtest, this time click Remember
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");

        // Sanity check, no logins should exist yet.
        var logins = pwmgr.getAllLogins();
        is(logins.length, 0, "Should not have any logins yet");

        clickPopupButton(popup, kRememberButton);
        break;

      case 5:
        // Same subtest, make sure we didn't prompt for an existing login.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(!popup, "checking for no notification popup");

        // Check to make sure we updated the timestamps and use count on the
        // existing login that was submitted for this form.
        var logins = pwmgr.getAllLogins();
        is(logins.length, 1, "Should only have 1 login");
        ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI");
        is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission");
        ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped");
        ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated");

        // remove that login
        pwmgr.removeLogin(login1);
        break;

      /* signons.rememberSignons pref tests... */

      case 6:
        // Same subtest, make sure we're getting the popup again.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        popup.remove();
        // Change prefs to no longer remember signons
        prefs.setBoolPref("rememberSignons", false);
        break;

      case 7:
        // Same subtest, make sure we're not prompting.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(!popup, "checking for no notification popup");
        // Change prefs to remember signons again
        prefs.setBoolPref("rememberSignons", true);
        break;

      case 8:
        // Same subtest, make sure we're getting the popup again.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        popup.remove();
        break;

      /* autocomplete=off tests... */

      case 9:
        // Check for notification popup when autocomplete=off present
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "checking for notification popup");
        popup.remove();
        break;

      case 10:
        // Check for notification popup when autocomplete=off present
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "checking for notification popup");
        popup.remove();
        break;

      case 11:
        // Check for notification popup when autocomplete=off present
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "checking for notification popup");
        popup.remove();
        break;

      /* no password field test... */

      case 12:
        // Check for no notification popup when no password field present
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "null",     "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(!popup, "checking for no notification popup");

        // Add login for the next test.
        pwmgr.addLogin(login2);
        break;

      case 13:
        // Check for update popup when existing pw-only login matches form.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(popup, "checking for notification popup");
        popup.remove();
        pwmgr.removeLogin(login2);

        // Add login for the next test
        pwmgr.addLogin(login1);
        break;

      case 14:
        // Check for no notification popup when pw-only form matches existing login.
        is(gotUser, "null",     "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(!popup, "checking for no notification popup");
        pwmgr.removeLogin(login1);

        // Add login for the next test
        pwmgr.addLogin(login2B);
        break;

      case 15:
        // Check for notification popup when existing pw-only login doesn't match form.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        pwmgr.removeLogin(login2B);
        popup.remove();

        // Add login for the next test
        pwmgr.addLogin(login1B);
        break;

      case 16:
        // Check for notification popup when pw-only form doesn't match existing login.
        is(gotUser, "null",     "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        pwmgr.removeLogin(login1B);
        popup.remove();

        // Add login for the next tests
        pwmgr.addLogin(login1);
        break;

      case 17:
        // Check for change-password popup, u+p login on u+p form. (not changed)
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "pass2",    "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(popup, "got notification popup");
        clickPopupButton(popup, kDontChangeButton);
        break;

      case 18:
        // Check for change-password popup, u+p login on u+p form.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "pass2",    "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(popup, "got notification popup");
        clickPopupButton(popup, kChangeButton);

        // Check to make sure we updated the timestamps and use count for
        // the login being changed with this form.
        var logins = pwmgr.getAllLogins();
        is(logins.length, 1, "Should only have 1 login");
        ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI");
        is(logins[0].timesUsed, 2, "check .timesUsed incremented on change");
        ok(logins[0].timeCreated < logins[0].timeLastUsed, "timeLastUsed bumped");
        ok(logins[0].timeLastUsed == logins[0].timePasswordChanged, "timeUsed == timeChanged");

        // cleanup
        login1.password = "pass2";
        pwmgr.removeLogin(login1);
        login1.password = "notifyp1";

        // Add login for the next test
        pwmgr.addLogin(login2);
        break;

      // ...can't change a u+p login on a p-only form...

      case 19:
        // Check for change-password popup, p-only login on u+p form.
        // (needed a different subtest for this because the login created in
        // test_0init was interfering)
        is(gotUser, "",         "Checking submitted username");
        is(gotPass, "pass2",    "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(popup, "got notification popup");
        clickPopupButton(popup, kChangeButton);
        break;

      case 20:
        // Check for change-password popup, p-only login on p-only form.
        is(gotUser, "null",     "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(popup, "got notification popup");
        clickPopupButton(popup, kChangeButton);

        pwmgr.removeLogin(login2);
        break;

      case 21:
        // Check text on a user+pass notification popup
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        // Check the text, which comes from the localized saveLoginText string.
        notificationText = popup.message;
        expectedText = "Would you like " + brandShortName + " to remember this login?";
        is(expectedText, notificationText, "Checking text: " + notificationText);
        popup.remove();
        break;

      case 22:
        // Check text on a user+pass notification popup, username is really long
        is(gotUser, "nowisthetimeforallgoodmentocometotheaidoftheircountry", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        // Check the text, which comes from the localized saveLoginText string.
        notificationText = popup.message;
        expectedText = "Would you like " + brandShortName + " to remember this login\?";
        is(expectedText, notificationText, "Checking text: " + notificationText);
        popup.remove();
        break;

      case 23:
        // Check text on a pass-only notification popup
        is(gotUser, "null",     "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        // Check the text, which comes from the localized saveLoginTextNoUser string.
        notificationText = popup.message;
        expectedText = "Would you like " + brandShortName + " to remember this password\?";
        is(expectedText, notificationText, "Checking text: " + notificationText);
        popup.remove();
        break;

      case 24:
        // Check for notification popup when a form with 2 password fields (no username) is
        // submitted and there are no saved logins.
        is(gotUser, "null", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");
        popup.remove();

        // Add login for the next test
        pwmgr.addLogin(login1B);
        break;

      case 25:
        // Check for notification popup when a form with 2 password fields (no username) is
        // submitted and there is a saved login with a username and different password.
        is(gotUser, "null", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(popup, "got notification popup");
        popup.remove();
        // remove that login
        pwmgr.removeLogin(login1B);

        // Add login for the next test
        pwmgr.addLogin(login2B);
        break;

      case 26:
        // Check for notification popup when a form with 2 password fields (no username) is
        // submitted and there is a saved login with no username and a different password.
        is(gotUser, "null", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(popup, "got notification popup");
        popup.remove();
        // remove that login
        pwmgr.removeLogin(login2B);

        // Add login for the next test
        pwmgr.addLogin(login1);

        break;

      case 27:
        // Check for no notification popup when a form with 2 password fields (no username) is
        // submitted and there is a saved login with a username and the same password.
        is(gotUser, "null", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(!popup, "checking for no notification popup");

        // Check to make sure we updated the timestamps and use count on the
        // existing login that was submitted for this form.
        var logins = pwmgr.getAllLogins();
        is(logins.length, 1, "Should only have 1 login");
        ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI");
        is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission");
        ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped");
        ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated");

        // remove that login
        pwmgr.removeLogin(login1);

        // Add login for the next test
        pwmgr.addLogin(login2);
        break;

      case 28:
        // Check for no notification popup when a form with 2 password fields (no username) is
        // submitted and there is a saved login with no username and the same password.
        is(gotUser, "null", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-change");
        ok(!popup, "checking for no notification popup");

        // Check to make sure we updated the timestamps and use count on the
        // existing login that was submitted for this form.
        var logins = pwmgr.getAllLogins();
        is(logins.length, 1, "Should only have 1 login");
        ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI");
        is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission");
        ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped");
        ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated");

        // remove that login
        pwmgr.removeLogin(login2);
        break;

      case 29: {
        // Check that we capture the proper fields when a field recipe is in use.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(popup, "got notification popup");

        // Sanity check, no logins should exist yet.
        let logins = pwmgr.getAllLogins();
        is(logins.length, 0, "Should not have any logins yet");

        clickPopupButton(popup, kRememberButton);
        break;
      }

      case 30: {
        // Same subtest, make sure we didn't prompt for an existing login.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(!popup, "checking for no notification popup");

        // Check to make sure we updated the timestamps and use count on the
        // existing login that was submitted for this form.
        let logins = pwmgr.getAllLogins();
        is(logins.length, 1, "Should only have 1 login");
        ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI");
        is(logins[0].username, "notifyu1", "check .username for existing login submission");
        is(logins[0].password, "notifyp1", "check .password for existing login submission");
        is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission");
        ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped");
        ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated");

        // remove the added login
        pwmgr.removeAllLogins();

        // Add login for the next test
        pwmgr.addLogin(login3);

        break;
      }

      case 31: {
        // make sure we didn't prompt for an existing login with different
        // scheme for formSubmitURL.
        is(gotUser, "notifyu1", "Checking submitted username");
        is(gotPass, "notifyp1", "Checking submitted password");
        popup = getPopup(popupNotifications, "password-save");
        ok(!popup, "checking for no notification popup");

        // Check to make sure we updated the timestamps and use count on the
        // existing login that was submitted for this form.
        var logins = pwmgr.getAllLogins();
        is(logins.length, 1, "Should only have 1 login");
        ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI");
        is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission");
        ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped");
        ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated");

        // remove that login
        pwmgr.removeAllLogins();
        break;
      }
      default:
        ok(false, "Unexpected call to checkTest for test #" + testNum);

    }

    // TODO:
    // * existing login test, form has different password --> change password, no save prompt
}

const Ci = SpecialPowers.Ci;
const Cc = SpecialPowers.Cc;
ok(Ci != null, "Access Ci");
ok(Cc != null, "Access Cc");

var pwmgr = Cc["@mozilla.org/login-manager;1"].
            getService(Ci.nsILoginManager);
ok(pwmgr != null, "Access pwmgr");

pwmgr.removeAllLogins();

var prefs = Cc["@mozilla.org/preferences-service;1"].
            getService(Ci.nsIPrefService);
ok(prefs != null, "Access prefs");
prefs = prefs.getBranch("signon.");
ok(prefs != null, "Access pref branch");

var nsLoginInfo = new SpecialPowers.wrap(SpecialPowers.Components).Constructor("@mozilla.org/login-manager/loginInfo;1",
                                             Ci.nsILoginInfo, "init");
var login1 = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
                             "notifyu1", "notifyp1", "user", "pass");
var login2 = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
                             "", "notifyp1", "", "pass");
var login1B = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
                              "notifyu1B", "notifyp1B", "user", "pass");
var login2B = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
                              "", "notifyp1B", "", "pass");
var login3 = new nsLoginInfo("http://mochi.test:8888", "https://mochi.test:8888", null,
                             "notifyu1", "notifyp1", "user", "pass");

var parentScriptURL = SimpleTest.getTestFileURL("pwmgr_common.js");
var mm = SpecialPowers.loadChromeScript(parentScriptURL);

var iframe = document.getElementById("iframe");
iframe.onload = handleLoad;

// popupNotifications (not *popup*) is a constant, per-tab container. So, we
// only need to fetch it once.
var popupNotifications = getPopupNotifications(window.top);
ok(popupNotifications, "Got popupNotifications");

var testNum = 1;

// Load recipes for this test.
mm.sendAsyncMessage("loadRecipes", {
  siteRecipes: [{
    hosts: ["example.org"],
    usernameSelector: "#user",
    passwordSelector: "#pass",
  }],
});

mm.addMessageListener("loadedRecipes", function loadedRecipes() {
  ok(true, "Starting test #" + testNum);
  iframe.src = subtests[testNum-1];
})

SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>