mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-15 03:39:00 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* Test the password manager context menu.
|
||||
*/
|
||||
|
||||
/* eslint no-shadow:"off" */
|
||||
|
||||
"use strict";
|
||||
|
||||
// The hostname for the test URIs.
|
||||
const TEST_HOSTNAME = "https://example.com";
|
||||
const MULTIPLE_FORMS_PAGE_PATH = "/browser/toolkit/components/passwordmgr/test/browser/multiple_forms.html";
|
||||
|
||||
const CONTEXT_MENU = document.getElementById("contentAreaContextMenu");
|
||||
const POPUP_HEADER = document.getElementById("fill-login");
|
||||
|
||||
/**
|
||||
* Initialize logins needed for the tests and disable autofill
|
||||
* for login forms for easier testing of manual fill.
|
||||
*/
|
||||
add_task(function* test_initialize() {
|
||||
Services.prefs.setBoolPref("signon.autofillForms", false);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("signon.autofillForms");
|
||||
Services.prefs.clearUserPref("signon.schemeUpgrades");
|
||||
});
|
||||
for (let login of loginList()) {
|
||||
Services.logins.addLogin(login);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the context menu is populated with the right
|
||||
* menuitems for the target password input field.
|
||||
*/
|
||||
add_task(function* test_context_menu_populate_password_noSchemeUpgrades() {
|
||||
Services.prefs.setBoolPref("signon.schemeUpgrades", false);
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: TEST_HOSTNAME + MULTIPLE_FORMS_PAGE_PATH,
|
||||
}, function* (browser) {
|
||||
yield openPasswordContextMenu(browser, "#test-password-1");
|
||||
|
||||
// Check the content of the password manager popup
|
||||
let popupMenu = document.getElementById("fill-login-popup");
|
||||
checkMenu(popupMenu, 2);
|
||||
|
||||
CONTEXT_MENU.hidePopup();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the context menu is populated with the right
|
||||
* menuitems for the target password input field.
|
||||
*/
|
||||
add_task(function* test_context_menu_populate_password_schemeUpgrades() {
|
||||
Services.prefs.setBoolPref("signon.schemeUpgrades", true);
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: TEST_HOSTNAME + MULTIPLE_FORMS_PAGE_PATH,
|
||||
}, function* (browser) {
|
||||
yield openPasswordContextMenu(browser, "#test-password-1");
|
||||
|
||||
// Check the content of the password manager popup
|
||||
let popupMenu = document.getElementById("fill-login-popup");
|
||||
checkMenu(popupMenu, 3);
|
||||
|
||||
CONTEXT_MENU.hidePopup();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the context menu is populated with the right menuitems
|
||||
* for the target username field with a password field present.
|
||||
*/
|
||||
add_task(function* test_context_menu_populate_username_with_password_noSchemeUpgrades() {
|
||||
Services.prefs.setBoolPref("signon.schemeUpgrades", false);
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: TEST_HOSTNAME + "/browser/toolkit/components/" +
|
||||
"passwordmgr/test/browser/multiple_forms.html",
|
||||
}, function* (browser) {
|
||||
yield openPasswordContextMenu(browser, "#test-username-2");
|
||||
|
||||
// Check the content of the password manager popup
|
||||
let popupMenu = document.getElementById("fill-login-popup");
|
||||
checkMenu(popupMenu, 2);
|
||||
|
||||
CONTEXT_MENU.hidePopup();
|
||||
});
|
||||
});
|
||||
/**
|
||||
* Check if the context menu is populated with the right menuitems
|
||||
* for the target username field with a password field present.
|
||||
*/
|
||||
add_task(function* test_context_menu_populate_username_with_password_schemeUpgrades() {
|
||||
Services.prefs.setBoolPref("signon.schemeUpgrades", true);
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: TEST_HOSTNAME + "/browser/toolkit/components/" +
|
||||
"passwordmgr/test/browser/multiple_forms.html",
|
||||
}, function* (browser) {
|
||||
yield openPasswordContextMenu(browser, "#test-username-2");
|
||||
|
||||
// Check the content of the password manager popup
|
||||
let popupMenu = document.getElementById("fill-login-popup");
|
||||
checkMenu(popupMenu, 3);
|
||||
|
||||
CONTEXT_MENU.hidePopup();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the password field is correctly filled when one
|
||||
* login menuitem is clicked.
|
||||
*/
|
||||
add_task(function* test_context_menu_password_fill() {
|
||||
Services.prefs.setBoolPref("signon.schemeUpgrades", true);
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: TEST_HOSTNAME + MULTIPLE_FORMS_PAGE_PATH,
|
||||
}, function* (browser) {
|
||||
let formDescriptions = yield ContentTask.spawn(browser, {}, function*() {
|
||||
let forms = Array.from(content.document.getElementsByClassName("test-form"));
|
||||
return forms.map((f) => f.getAttribute("description"));
|
||||
});
|
||||
|
||||
for (let description of formDescriptions) {
|
||||
info("Testing form: " + description);
|
||||
|
||||
let passwordInputIds = yield ContentTask.spawn(browser, {description}, function*({description}) {
|
||||
let formElement = content.document.querySelector(`[description="${description}"]`);
|
||||
let passwords = Array.from(formElement.querySelectorAll("input[type='password']"));
|
||||
return passwords.map((p) => p.id);
|
||||
});
|
||||
|
||||
for (let inputId of passwordInputIds) {
|
||||
info("Testing password field: " + inputId);
|
||||
|
||||
// Synthesize a right mouse click over the username input element.
|
||||
yield openPasswordContextMenu(browser, "#" + inputId, function*() {
|
||||
let inputDisabled = yield ContentTask
|
||||
.spawn(browser, {inputId}, function*({inputId}) {
|
||||
let input = content.document.getElementById(inputId);
|
||||
return input.disabled || input.readOnly;
|
||||
});
|
||||
|
||||
// If the password field is disabled or read-only, we want to see
|
||||
// the disabled Fill Password popup header.
|
||||
if (inputDisabled) {
|
||||
Assert.ok(!POPUP_HEADER.hidden, "Popup menu is not hidden.");
|
||||
Assert.ok(POPUP_HEADER.disabled, "Popup menu is disabled.");
|
||||
CONTEXT_MENU.hidePopup();
|
||||
}
|
||||
|
||||
return !inputDisabled;
|
||||
});
|
||||
|
||||
if (CONTEXT_MENU.state != "open") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The only field affected by the password fill
|
||||
// should be the target password field itself.
|
||||
yield assertContextMenuFill(browser, description, null, inputId, 1);
|
||||
yield ContentTask.spawn(browser, {inputId}, function*({inputId}) {
|
||||
let passwordField = content.document.getElementById(inputId);
|
||||
Assert.equal(passwordField.value, "password1", "Check upgraded login was actually used");
|
||||
});
|
||||
|
||||
CONTEXT_MENU.hidePopup();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the form is correctly filled when one
|
||||
* username context menu login menuitem is clicked.
|
||||
*/
|
||||
add_task(function* test_context_menu_username_login_fill() {
|
||||
Services.prefs.setBoolPref("signon.schemeUpgrades", true);
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: TEST_HOSTNAME + MULTIPLE_FORMS_PAGE_PATH,
|
||||
}, function* (browser) {
|
||||
|
||||
let formDescriptions = yield ContentTask.spawn(browser, {}, function*() {
|
||||
let forms = Array.from(content.document.getElementsByClassName("test-form"));
|
||||
return forms.map((f) => f.getAttribute("description"));
|
||||
});
|
||||
|
||||
for (let description of formDescriptions) {
|
||||
info("Testing form: " + description);
|
||||
let usernameInputIds = yield ContentTask
|
||||
.spawn(browser, {description}, function*({description}) {
|
||||
let formElement = content.document.querySelector(`[description="${description}"]`);
|
||||
let inputs = Array.from(formElement.querySelectorAll("input[type='text']"));
|
||||
return inputs.map((p) => p.id);
|
||||
});
|
||||
|
||||
for (let inputId of usernameInputIds) {
|
||||
info("Testing username field: " + inputId);
|
||||
|
||||
// Synthesize a right mouse click over the username input element.
|
||||
yield openPasswordContextMenu(browser, "#" + inputId, function*() {
|
||||
let headerHidden = POPUP_HEADER.hidden;
|
||||
let headerDisabled = POPUP_HEADER.disabled;
|
||||
|
||||
let data = {description, inputId, headerHidden, headerDisabled};
|
||||
let shouldContinue = yield ContentTask.spawn(browser, data, function*(data) {
|
||||
let {description, inputId, headerHidden, headerDisabled} = data;
|
||||
let formElement = content.document.querySelector(`[description="${description}"]`);
|
||||
let usernameField = content.document.getElementById(inputId);
|
||||
// We always want to check if the first password field is filled,
|
||||
// since this is the current behavior from the _fillForm function.
|
||||
let passwordField = formElement.querySelector("input[type='password']");
|
||||
|
||||
// If we don't want to see the actual popup menu,
|
||||
// check if the popup is hidden or disabled.
|
||||
if (!passwordField || usernameField.disabled || usernameField.readOnly ||
|
||||
passwordField.disabled || passwordField.readOnly) {
|
||||
if (!passwordField) {
|
||||
Assert.ok(headerHidden, "Popup menu is hidden.");
|
||||
} else {
|
||||
Assert.ok(!headerHidden, "Popup menu is not hidden.");
|
||||
Assert.ok(headerDisabled, "Popup menu is disabled.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!shouldContinue) {
|
||||
CONTEXT_MENU.hidePopup();
|
||||
}
|
||||
|
||||
return shouldContinue;
|
||||
});
|
||||
|
||||
if (CONTEXT_MENU.state != "open") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let passwordFieldId = yield ContentTask
|
||||
.spawn(browser, {description}, function*({description}) {
|
||||
let formElement = content.document.querySelector(`[description="${description}"]`);
|
||||
return formElement.querySelector("input[type='password']").id;
|
||||
});
|
||||
|
||||
// We shouldn't change any field that's not the target username field or the first password field
|
||||
yield assertContextMenuFill(browser, description, inputId, passwordFieldId, 1);
|
||||
|
||||
yield ContentTask.spawn(browser, {passwordFieldId}, function*({passwordFieldId}) {
|
||||
let passwordField = content.document.getElementById(passwordFieldId);
|
||||
if (!passwordField.hasAttribute("expectedFail")) {
|
||||
Assert.equal(passwordField.value, "password1", "Check upgraded login was actually used");
|
||||
}
|
||||
});
|
||||
|
||||
CONTEXT_MENU.hidePopup();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Synthesize mouse clicks to open the password manager context menu popup
|
||||
* for a target password input element.
|
||||
*
|
||||
* assertCallback should return true if we should continue or else false.
|
||||
*/
|
||||
function* openPasswordContextMenu(browser, passwordInput, assertCallback = null) {
|
||||
// Synthesize a right mouse click over the password input element.
|
||||
let contextMenuShownPromise = BrowserTestUtils.waitForEvent(CONTEXT_MENU, "popupshown");
|
||||
let eventDetails = {type: "contextmenu", button: 2};
|
||||
BrowserTestUtils.synthesizeMouseAtCenter(passwordInput, eventDetails, browser);
|
||||
yield contextMenuShownPromise;
|
||||
|
||||
if (assertCallback) {
|
||||
let shouldContinue = yield assertCallback();
|
||||
if (!shouldContinue) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Synthesize a mouse click over the fill login menu header.
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(POPUP_HEADER, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(POPUP_HEADER, {});
|
||||
yield popupShownPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that only the expected form fields are filled.
|
||||
*/
|
||||
function* assertContextMenuFill(browser, formId, usernameFieldId, passwordFieldId, loginIndex) {
|
||||
let popupMenu = document.getElementById("fill-login-popup");
|
||||
let unchangedSelector = `[description="${formId}"] input:not(#${passwordFieldId})`;
|
||||
|
||||
if (usernameFieldId) {
|
||||
unchangedSelector += `:not(#${usernameFieldId})`;
|
||||
}
|
||||
|
||||
yield ContentTask.spawn(browser, {unchangedSelector}, function*({unchangedSelector}) {
|
||||
let unchangedFields = content.document.querySelectorAll(unchangedSelector);
|
||||
|
||||
// Store the value of fields that should remain unchanged.
|
||||
if (unchangedFields.length) {
|
||||
for (let field of unchangedFields) {
|
||||
field.setAttribute("original-value", field.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Execute the default command of the specified login menuitem found in the context menu.
|
||||
let loginItem = popupMenu.getElementsByClassName("context-login-item")[loginIndex];
|
||||
|
||||
// Find the used login by it's username (Use only unique usernames in this test).
|
||||
let {username, password} = getLoginFromUsername(loginItem.label);
|
||||
|
||||
let data = {username, password, usernameFieldId, passwordFieldId, formId, unchangedSelector};
|
||||
let continuePromise = ContentTask.spawn(browser, data, function*(data) {
|
||||
let {username, password, usernameFieldId, passwordFieldId, formId, unchangedSelector} = data;
|
||||
let form = content.document.querySelector(`[description="${formId}"]`);
|
||||
yield ContentTaskUtils.waitForEvent(form, "input", "Username input value changed");
|
||||
|
||||
if (usernameFieldId) {
|
||||
let usernameField = content.document.getElementById(usernameFieldId);
|
||||
|
||||
// If we have an username field, check if it's correctly filled
|
||||
if (usernameField.getAttribute("expectedFail") == null) {
|
||||
Assert.equal(username, usernameField.value, "Username filled and correct.");
|
||||
}
|
||||
}
|
||||
|
||||
if (passwordFieldId) {
|
||||
let passwordField = content.document.getElementById(passwordFieldId);
|
||||
|
||||
// If we have a password field, check if it's correctly filled
|
||||
if (passwordField && passwordField.getAttribute("expectedFail") == null) {
|
||||
Assert.equal(password, passwordField.value, "Password filled and correct.");
|
||||
}
|
||||
}
|
||||
|
||||
let unchangedFields = content.document.querySelectorAll(unchangedSelector);
|
||||
|
||||
// Check that all fields that should not change have the same value as before.
|
||||
if (unchangedFields.length) {
|
||||
Assert.ok(() => {
|
||||
for (let field of unchangedFields) {
|
||||
if (field.value != field.getAttribute("original-value")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, "Other fields were not changed.");
|
||||
}
|
||||
});
|
||||
|
||||
loginItem.doCommand();
|
||||
|
||||
return continuePromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if every login that matches the page hostname are available at the context menu.
|
||||
* @param {Element} contextMenu
|
||||
* @param {Number} expectedCount - Number of logins expected in the context menu. Used to ensure
|
||||
* we continue testing something useful.
|
||||
*/
|
||||
function checkMenu(contextMenu, expectedCount) {
|
||||
let logins = loginList().filter(login => {
|
||||
return LoginHelper.isOriginMatching(login.hostname, TEST_HOSTNAME, {
|
||||
schemeUpgrades: Services.prefs.getBoolPref("signon.schemeUpgrades"),
|
||||
});
|
||||
});
|
||||
// Make an array of menuitems for easier comparison.
|
||||
let menuitems = [...CONTEXT_MENU.getElementsByClassName("context-login-item")];
|
||||
Assert.equal(menuitems.length, expectedCount, "Expected number of menu items");
|
||||
Assert.ok(logins.every(l => menuitems.some(m => l.username == m.label)), "Every login have an item at the menu.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a login by it's username.
|
||||
*
|
||||
* Only unique login/hostname combinations should be used at this test.
|
||||
*/
|
||||
function getLoginFromUsername(username) {
|
||||
return loginList().find(login => login.username == username);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of logins used for the test.
|
||||
*
|
||||
* We should only use unique usernames in this test,
|
||||
* because we need to search logins by username. There is one duplicate u+p combo
|
||||
* in order to test de-duping in the menu.
|
||||
*/
|
||||
function loginList() {
|
||||
return [
|
||||
LoginTestUtils.testData.formLogin({
|
||||
hostname: "https://example.com",
|
||||
formSubmitURL: "https://example.com",
|
||||
username: "username",
|
||||
password: "password",
|
||||
}),
|
||||
// Same as above but HTTP in order to test de-duping.
|
||||
LoginTestUtils.testData.formLogin({
|
||||
hostname: "http://example.com",
|
||||
formSubmitURL: "http://example.com",
|
||||
username: "username",
|
||||
password: "password",
|
||||
}),
|
||||
LoginTestUtils.testData.formLogin({
|
||||
hostname: "http://example.com",
|
||||
formSubmitURL: "http://example.com",
|
||||
username: "username1",
|
||||
password: "password1",
|
||||
}),
|
||||
LoginTestUtils.testData.formLogin({
|
||||
hostname: "https://example.com",
|
||||
formSubmitURL: "https://example.com",
|
||||
username: "username2",
|
||||
password: "password2",
|
||||
}),
|
||||
LoginTestUtils.testData.formLogin({
|
||||
hostname: "http://example.org",
|
||||
formSubmitURL: "http://example.org",
|
||||
username: "username-cross-origin",
|
||||
password: "password-cross-origin",
|
||||
}),
|
||||
];
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue