Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'android' OR os == 'android' && debug OR http3 OR http2
- Manifest: toolkit/components/passwordmgr/test/mochitest/mochitest.toml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test capturing of fields outside of a form</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="pwmgr_common.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="application/javascript">
const { LoginFormFactory } = SpecialPowers.ChromeUtils.importESModule(
"resource://gre/modules/shared/LoginFormFactory.sys.mjs"
);
const { LoginManagerChild } = SpecialPowers.ChromeUtils.importESModule(
"resource://gre/modules/LoginManagerChild.sys.mjs"
);
function loadFrame() {
return new Promise(resolve => {
document.getElementById("loginFrame").addEventListener("load", (evt) => {
if (evt.target.contentWindow.location.href.includes("blank.html")) {
resolve();
}
});
});
}
let loadPromise = new Promise(resolve => {
document.addEventListener("DOMContentLoaded", () => {
resolve(loadFrame());
});
});
add_setup(async () => {
info("Waiting for page and frame loads");
await loadPromise;
await loadRecipes({
siteRecipes: [{
hosts: ["mochi.test:8888"],
usernameSelector: "input[name='recipeuname']",
passwordSelector: "input[name='recipepword']",
}],
});
});
const TESTCASES = [
{
// Inputs
document: `<input type=password value="">`,
selectorValues: {
"[type=password]": "pass1",
},
inputIndexForFormLike: 0,
expectedFormsCount: 1,
// Expected outputs similar to PasswordManager:onFormSubmit
origin: DEFAULT_ORIGIN,
formActionOrigin: DEFAULT_ORIGIN,
usernameFieldValue: null,
newPasswordFieldValue: "pass1",
oldPasswordFieldValue: null,
},
{
document: `<input id="u1" value="">
<input type=password value="">`,
selectorValues: {
"#u1": "user1",
"[type=password]": "pass1",
},
inputIndexForFormLike: 0,
expectedFormsCount: 1,
origin: DEFAULT_ORIGIN,
formActionOrigin: DEFAULT_ORIGIN,
usernameFieldValue: "user1",
newPasswordFieldValue: "pass1",
oldPasswordFieldValue: null,
},
{
document: `<input id="u1" value="">
<input type=password value="">`,
selectorValues: {
"#u1": "user1",
"[type=password]": "pass1",
},
inputIndexForFormLike: 1,
expectedFormsCount: 1,
origin: DEFAULT_ORIGIN,
formActionOrigin: DEFAULT_ORIGIN,
usernameFieldValue: "user1",
newPasswordFieldValue: "pass1",
oldPasswordFieldValue: null,
},
{
document: `<input id="u1" value="">
<input id="p1" type=password value="">
<input id="p2" type=password value="">`,
selectorValues: {
"#u1": "user1",
"#p1": "pass1",
"#p2": "pass2",
},
inputIndexForFormLike: 2,
expectedFormsCount: 1,
origin: DEFAULT_ORIGIN,
formActionOrigin: DEFAULT_ORIGIN,
usernameFieldValue: "user1",
newPasswordFieldValue: "pass2",
oldPasswordFieldValue: "pass1",
},
{
document: `<input id="u1" value="">
<input id="p1" type=password value="">
<input id="p2" type=password value="">
<input id="p3" type=password value="">`,
selectorValues: {
"#u1": "user1",
"#p1": "pass1",
"#p2": "pass2",
"#p3": "pass2",
},
inputIndexForFormLike: 3,
expectedFormsCount: 1,
origin: DEFAULT_ORIGIN,
formActionOrigin: DEFAULT_ORIGIN,
usernameFieldValue: "user1",
newPasswordFieldValue: "pass2",
oldPasswordFieldValue: "pass1",
},
{
document: `<input id="u1" value="">
<input id="p1" type=password value="" form="form1">
<input id="p2" type=password value="">
<form id="form1">
<input id="u2" value="">
<input id="p3" type=password value="">
</form>`,
selectorValues: {
"#u1": "user1",
"#p1": "user2",
"#p2": "pass1",
"#u2": "user3",
"#p3": "pass2",
},
inputIndexForFormLike: 2,
expectedFormsCount: 2,
origin: DEFAULT_ORIGIN,
formActionOrigin: DEFAULT_ORIGIN,
usernameFieldValue: "user1",
newPasswordFieldValue: "pass1",
oldPasswordFieldValue: null,
},
{
document: `<!-- recipe field override -->
<input name="recipeuname" value="">
<input id="u1" value="">
<input id="p1" type=password value="">
<input name="recipepword" type=password value="">`,
selectorValues: {
"[name='recipeuname']": "username from recipe",
"#u1": "default field username",
"#p1": "pass1",
"[name='recipepword']": "pass2",
},
inputIndexForFormLike: 2,
expectedFormsCount: 1,
origin: DEFAULT_ORIGIN,
formActionOrigin: DEFAULT_ORIGIN,
usernameFieldValue: "username from recipe",
newPasswordFieldValue: "pass2",
oldPasswordFieldValue: null,
},
];
let count = 0;
async function testFormlessSubmit(tc) {
let loginFrame = document.getElementById("loginFrame");
let frameDoc = SpecialPowers.wrap(loginFrame.contentWindow).document;
info("Starting testcase: " + JSON.stringify(tc));
let formsProcessed = promiseFormsProcessedInSameProcess(tc.expectedFormsCount);
frameDoc.documentElement.innerHTML = tc.document;
await formsProcessed;
// We eliminate no user input as a reason for not capturing by modifying the value
setUserInputValues(frameDoc.documentElement, tc.selectorValues);
let inputForFormLike = frameDoc.querySelectorAll("input")[tc.inputIndexForFormLike];
let formLike = LoginFormFactory.createFromField(inputForFormLike);
info("Calling _onFormSubmit with FormLike");
let submitProcessed = getSubmitMessage();
LoginManagerChild.forWindow(frameDoc.defaultView)._onFormSubmit(formLike);
let { origin, data } = await submitProcessed;
// Check data sent via PasswordManager:onFormSubmit
is(origin, tc.origin, "Check origin");
is(data.formActionOrigin, tc.formActionOrigin, "Check formActionOrigin");
if (tc.usernameFieldValue === null) {
is(data.usernameField, tc.usernameFieldValue, "Check usernameField");
} else {
is(data.usernameField.value, tc.usernameFieldValue, "Check usernameField");
}
is(data.newPasswordField.value, tc.newPasswordFieldValue, "Check newPasswordFieldValue");
if (tc.oldPasswordFieldValue === null) {
is(data.oldPasswordField, tc.oldPasswordFieldValue, "Check oldPasswordFieldValue");
} else {
is(data.oldPasswordField.value, tc.oldPasswordFieldValue, "Check oldPasswordFieldValue");
}
loadPromise = loadFrame();
loginFrame.contentWindow.location =
await loadPromise;
}
for (let tc of TESTCASES) {
let taskName = "testcase-" + count++;
let tmp = {
async [taskName]() {
await testFormlessSubmit(tc);
},
};
add_task(tmp[taskName]);
}
</script>
<p id="display"></p>
<div id="content">
<iframe id="loginFrame" src="http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/mochitest/blank.html"></iframe>
</div>
<pre id="test"></pre>
</body>
</html>