Bug 1243729 - (m-b) Part II, Test on username selection dialog, r=MattN, a=lizzard

MozReview-Commit-ID: 3OKA17mVjMs
This commit is contained in:
Timothy Guan-tin Chien 2016-04-20 12:49:38 +08:00
parent cacbaf2742
commit f53414a463
5 changed files with 312 additions and 0 deletions

View File

@ -243,3 +243,15 @@ this.LoginTestUtils.testData = {
];
},
};
this.LoginTestUtils.recipes = {
getRecipeParent() {
let { LoginManagerParent } = Cu.import("resource://gre/modules/LoginManagerParent.jsm", {});
if (!LoginManagerParent.recipeParentPromise) {
return null;
}
return LoginManagerParent.recipeParentPromise.then((recipeParent) => {
return recipeParent;
});
},
};

View File

@ -1,12 +1,17 @@
[DEFAULT]
support-files =
../formsubmit.sjs
../subtst_notifications_change_p.html
authenticate.sjs
form_basic.html
head.js
insecure_test.html
insecure_test_subframe.html
multiple_forms.html
streamConverter_content.sjs
[browser_username_select_dialog.js]
skip-if = e10s # bug 1263760
[browser_DOMFormHasPassword.js]
[browser_DOMInputPasswordAdded.js]
[browser_filldoorhanger.js]

View File

@ -0,0 +1,144 @@
/*
* Test username selection dialog, on password update from a p-only form,
* when there are multiple saved logins on the domain.
*/
// Copied from prompt_common.js. TODO: share the code.
function getSelectDialogDoc() {
// Trudge through all the open windows, until we find the one
// that has selectDialog.xul loaded.
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
//var enumerator = wm.getEnumerator("navigator:browser");
var enumerator = wm.getXULWindowEnumerator(null);
while (enumerator.hasMoreElements()) {
var win = enumerator.getNext();
var windowDocShell = win.QueryInterface(Ci.nsIXULWindow).docShell;
var containedDocShells = windowDocShell.getDocShellEnumerator(
Ci.nsIDocShellTreeItem.typeChrome,
Ci.nsIDocShell.ENUMERATE_FORWARDS);
while (containedDocShells.hasMoreElements()) {
// Get the corresponding document for this docshell
var childDocShell = containedDocShells.getNext();
// We don't want it if it's not done loading.
if (childDocShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
continue;
var childDoc = childDocShell.QueryInterface(Ci.nsIDocShell)
.contentViewer
.DOMDocument;
if (childDoc.location.href == "chrome://global/content/selectDialog.xul")
return childDoc;
}
}
return null;
}
let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo, "init");
let login1 = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
"notifyu1", "notifyp1", "user", "pass");
let login1B = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
"notifyu1B", "notifyp1B", "user", "pass");
add_task(function* test_changeUPLoginOnPUpdateForm_accept() {
info("Select an u+p login from multiple logins, on password update form, and accept.");
Services.logins.addLogin(login1);
Services.logins.addLogin(login1B);
yield testSubmittingLoginForm("subtst_notifications_change_p.html", function*(fieldValues) {
is(fieldValues.username, "null", "Checking submitted username");
is(fieldValues.password, "pass2", "Checking submitted password");
yield ContentTaskUtils.waitForCondition(() => {
return getSelectDialogDoc();
}, "Wait for selection dialog to be accessible.");
let doc = getSelectDialogDoc();
let dialog = doc.getElementsByTagName("dialog")[0];
let listbox = doc.getElementById("list");
is(listbox.selectedIndex, 0, "Checking selected index");
is(listbox.itemCount, 2, "Checking selected length");
['notifyu1', 'notifyu1B'].forEach((username, i) => {
is(listbox.getItemAtIndex(i).label, username, "Check username selection on dialog");
});
dialog.acceptDialog();
yield ContentTaskUtils.waitForCondition(() => {
return !getSelectDialogDoc();
}, "Wait for selection dialog to disappear.");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 2, "Should have 2 logins");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "pass2", "Check the password changed");
is(login.timesUsed, 2, "Check times used");
login = SpecialPowers.wrap(logins[1]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1B", "Check the username unchanged");
is(login.password, "notifyp1B", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
// cleanup
login1.password = "pass2";
Services.logins.removeLogin(login1);
login1.password = "notifyp1";
Services.logins.removeLogin(login1B);
});
add_task(function* test_changeUPLoginOnPUpdateForm_cancel() {
info("Select an u+p login from multiple logins, on password update form, and cancel.");
Services.logins.addLogin(login1);
Services.logins.addLogin(login1B);
yield testSubmittingLoginForm("subtst_notifications_change_p.html", function*(fieldValues) {
is(fieldValues.username, "null", "Checking submitted username");
is(fieldValues.password, "pass2", "Checking submitted password");
yield ContentTaskUtils.waitForCondition(() => {
return getSelectDialogDoc();
}, "Wait for selection dialog to be accessible.");
let doc = getSelectDialogDoc();
let dialog = doc.getElementsByTagName("dialog")[0];
let listbox = doc.getElementById("list");
is(listbox.selectedIndex, 0, "Checking selected index");
is(listbox.itemCount, 2, "Checking selected length");
['notifyu1', 'notifyu1B'].forEach((username, i) => {
is(listbox.getItemAtIndex(i).label, username, "Check username selection on dialog");
});
dialog.cancelDialog();
yield ContentTaskUtils.waitForCondition(() => {
return !getSelectDialogDoc();
}, "Wait for selection dialog to disappear.");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 2, "Should have 2 logins");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "notifyp1", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
login = SpecialPowers.wrap(logins[1]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1B", "Check the username unchanged");
is(login.password, "notifyp1B", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
// cleanup
Services.logins.removeLogin(login1);
Services.logins.removeLogin(login1B);
});

View File

@ -0,0 +1,119 @@
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(recipeParent => recipeParent.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://mochi.test:8888"] - origin of the server to
* use to load `aPageFile`.
*/
function testSubmittingLoginForm(aPageFile, aTaskFn, aOrigin = "http://mochi.test:8888") {
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`
* @return the found password popup notification.
*/
function getCaptureDoorhanger(aKind) {
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();
}
}
// End popup notification (doorhanger) functions //

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Subtest for Login Manager notifications</title>
</head>
<body>
<h2>Change password</h2>
<form id="form" action="formsubmit.sjs">
<input id="pass_current" name="pass_current" type="password" value="notifyp1">
<input id="pass" name="pass" type="password">
<input id="pass_confirm" name="pass_confirm" type="password">
<button type='submit'>Submit</button>
</form>
<script>
function submitForm() {
passField.value = "pass2";
passConfirmField.value = "pass2";
form.submit();
}
window.onload = submitForm;
var form = document.getElementById("form");
var userField = document.getElementById("user");
var passField = document.getElementById("pass");
var passConfirmField = document.getElementById("pass_confirm");
</script>
</body>
</html>