Bug 1958269 - Handle form change where all previously detected fields get disconnected r=dimi,credential-management-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D245223
This commit is contained in:
Janika
2025-04-18 18:26:53 +00:00
parent 344b0d053d
commit 4782d52eca
9 changed files with 197 additions and 20 deletions

View File

@@ -10,6 +10,7 @@ support-files = [
"../fixtures/dynamic_formless_fields_updated_due_to_node_mutations.html",
"../fixtures/dynamic_formless_fields_updated_due_to_visiblity_state_change.html",
"../fixtures/dynamic_form_changing_on_user_interaction.html",
"../fixtures/dynamic_form_replacing_all_fields.html",
"../fixtures/page_navigation.html",
"./empty.html",
"../fixtures/**",

View File

@@ -196,6 +196,72 @@ add_task(
}
);
add_task(
async function address_fields_filled_in_form_after_all_fields_replaced() {
await BrowserTestUtils.withNewTab(
FORMS_REPLACING_ALL_FIELDS_ON_INPUT,
async browser => {
const selectorToTriggerAutocompletion = "#email-node-addition";
const elementValueToVerifyAutofill = TEST_ADDRESS_1.email;
info("Triggering autocompletion.");
await openPopupOn(browser, selectorToTriggerAutocompletion);
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
const filledOnFormChangePromise = TestUtils.topicObserved(
"formautofill-fill-after-form-change-complete"
);
await waitForAutofill(
browser,
selectorToTriggerAutocompletion,
elementValueToVerifyAutofill
);
info(
`Waiting for "formautofill-fill-after-form-change-complete" notification`
);
await filledOnFormChangePromise;
info("Verify new fields that replaced the old fields are autofilled");
const expectedAdditionalFieldsNotFilled = {
fields: [
{ fieldName: "name", autofill: "John R. Smith" },
{ fieldName: "email", autofill: TEST_ADDRESS_1.email },
{ fieldName: "tel", autofill: TEST_ADDRESS_1.tel },
{ fieldName: "country", autofill: TEST_ADDRESS_1.country },
{
fieldName: "street-address",
autofill: TEST_ADDRESS_1["street-address"].replace("\n", " "),
},
{
fieldName: "address-level1",
autofill: TEST_ADDRESS_1["address-level1"],
},
{
fieldName: "address-level2",
autofill: TEST_ADDRESS_1["address-level2"],
},
{
fieldName: "postal-code",
autofill: TEST_ADDRESS_1["postal-code"],
},
],
};
const actor =
browser.browsingContext.currentWindowGlobal.getActor("FormAutofill");
const section = Array.from(actor.sectionsByRootId.values()).flat()[0];
await verifyAutofillResult(
browser,
section,
expectedAdditionalFieldsNotFilled
);
}
);
}
);
/**
* Tests that additional fields are not filled when the form change was initiated
* by a user interaction that triggered a "click" event on the form.

View File

@@ -154,14 +154,20 @@ async function checkFormChangeHappened(formId) {
0
);
const fieldDetectedAfterFieldMutations =
const fieldDetectedAfterRemovingField =
getFieldDetectionCompletedPromiseResolver();
// This is for checking the changes of element removed and added then.
removeInputField(browser, `#${formId} input[name=address-level2]`);
await fieldDetectedAfterRemovingField;
const fieldDetectedAfterAddingField =
getFieldDetectionCompletedPromiseResolver();
addInputField(browser, formId, "address-level2");
await fieldDetectedAfterFieldMutations;
await fieldDetectedAfterAddingField;
await openPopupOn(browser, `#${formId} input[name=address-level2]`);

View File

@@ -86,6 +86,8 @@ const FORM_IFRAME_SANDBOXED_URL =
"https://example.org" + HTTP_TEST_PATH + "autocomplete_iframe_sandboxed.html";
const FORMS_WITH_DYNAMIC_FORM_CHANGE =
"https://example.org" + HTTP_TEST_PATH + "dynamic_forms.html";
const FORMS_REPLACING_ALL_FIELDS_ON_INPUT =
"https://example.org" + HTTP_TEST_PATH + "dynamic_forms.html";
const FORM_WITH_USER_INITIATED_FORM_CHANGE =
"https://example.org" +
HTTP_TEST_PATH +

View File

@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- Address form adding and removing nodes dynamically on user input -->
<form id="address-form-node-addition">
<label for="name-node-addition">Name</label>
<input type="text" id="name-node-addition" autocomplete="name">
<label for="email-node-addition">Email</label>
<input type="email" id="email-node-addition" autocomplete="email">
<label for="phone-node-addition">Phone</label>
<input type="tel" id="phone-node-addition" autocomplete="tel">
<label for="country-node-addition">Country</label>
<input type="text" id="country-node-addition" autocomplete="country">
<label for="street-address-node-addition">Street Address</label>
<input id="street-address-node-addition" type="text" autocomplete="street-address">
<label for="address-level1-node-addition">Address Level 1</label>
<input id="address-level1-node-addition" type="text" autocomplete="address-level1">
<label for="address-level2-node-addition">Address Level 2</label>
<input id="address-level2-node-addition" type="text" autocomplete="address-level2">
<label for="postal-code-node-addition">Postal Code</label>
<input id="postal-code-node-addition" type="text" autocomplete="postal-code">
</form>
<script>
const countryInputNodeAddition = document.getElementById("country-node-addition");
countryInputNodeAddition.addEventListener('input', () => {
const form = document.getElementById("address-form-node-addition");
const children = Array.from(form.children);
form.replaceChildren();
children.forEach((child, _) => {
// Alter the children to simulate fields replacement
const newChild = child.cloneNode(true);
newChild.id = newChild.id + "-after-form-change";
newChild.value = ""
form.append(newChild);
});
});
</script>
</html>