Bug 1373130 - Send message after identifyAutofillFields being invoked to indicate that formautofill is ready to open popup. r=lchang

MozReview-Commit-ID: 4dZzgYNahEq

--HG--
extra : rebase_source : 8faccab13a22dc6eab935f35be63560cdcb6c39e
This commit is contained in:
Ray Lin 2017-10-16 18:10:02 +08:00
parent 1daa7b40ab
commit aea39ef395
4 changed files with 76 additions and 27 deletions

View File

@ -36,6 +36,9 @@ var FormAutofillFrameScript = {
FormAutofillContent.identifyAutofillFields(this._nextHandleElement);
this._hasPendingTask = false;
this._nextHandleElement = null;
// This is for testing purpose only which sends a message to indicate that the
// form has been identified, and ready to open popup.
sendAsyncMessage("FormAutofill:FieldsIdentified");
});
},

View File

@ -98,6 +98,44 @@ async function sleep(ms = 500) {
await new Promise(resolve => setTimeout(resolve, ms));
}
async function focusAndWaitForFieldsIdentified(browser, selector) {
/* eslint no-shadow: ["error", { "allow": ["selector", "previouslyFocused", "previouslyIdentified"] }] */
const {previouslyFocused, previouslyIdentified} = await ContentTask.spawn(browser, {selector}, async function({selector}) {
Components.utils.import("resource://gre/modules/FormLikeFactory.jsm");
const input = content.document.querySelector(selector);
const rootElement = FormLikeFactory.findRootForField(input);
const previouslyFocused = content.document.activeElement == input;
const previouslyIdentified = rootElement.hasAttribute("test-formautofill-identified");
input.focus();
return {previouslyFocused, previouslyIdentified};
});
if (previouslyIdentified) {
return;
}
// Once the input is previously focused, no more FormAutofill:FieldsIdentified will be
// sent as the message goes along with focus event.
if (!previouslyFocused) {
await new Promise(resolve => {
Services.mm.addMessageListener("FormAutofill:FieldsIdentified", function onIdentified() {
Services.mm.removeMessageListener("FormAutofill:FieldsIdentified", onIdentified);
resolve();
});
});
}
// Wait 500ms to ensure that "markAsAutofillField" is completely finished.
await sleep();
await ContentTask.spawn(browser, {}, async function() {
Components.utils.import("resource://gre/modules/FormLikeFactory.jsm");
FormLikeFactory
.findRootForField(content.document.activeElement)
.setAttribute("test-formautofill-identified", "true");
});
}
async function expectPopupOpen(browser) {
const {autoCompletePopup} = browser;
const listItemElems = getDisplayedPopupItems(browser);
@ -116,23 +154,7 @@ async function expectPopupOpen(browser) {
async function openPopupOn(browser, selector) {
await SimpleTest.promiseFocus(browser);
/* eslint no-shadow: ["error", { "allow": ["selector"] }] */
const identified = await ContentTask.spawn(browser, {selector}, async function({selector}) {
const input = content.document.querySelector(selector);
const forms = content.document.getElementsByTagName("form");
const rootElement = [...forms].find(form => form.contains(input)) || content.document.body;
input.focus();
if (rootElement.hasAttribute("test-formautofill-identified")) {
return true;
}
rootElement.setAttribute("test-formautofill-identified", "true");
return false;
});
// Wait 2 seconds for identifyAutofillFields if the form hasn't been identified yet.
if (!identified) {
await sleep(2000);
}
await focusAndWaitForFieldsIdentified(browser, selector);
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
await expectPopupOpen(browser);
}

View File

@ -14,18 +14,38 @@ async function sleep(ms = 500, reason = "Intentionally wait for UI ready") {
await new Promise(resolve => setTimeout(resolve, ms));
}
async function setInput(selector, value) {
let input = document.querySelector("input" + selector);
input.value = value;
async function focusAndWaitForFieldsIdentified(input) {
const rootElement = input.form || input.ownerDocument.documentElement;
const previouslyFocused = input != document.activeElement;
input.focus();
// "identifyAutofillFields" is invoked asynchronously in "focusin" event. We
// should make sure fields are ready for popup before doing tests.
//
// TODO: "sleep" is used here temporarily because there's no event to
// notify us of the state of "identifyAutofillFields" for now. We should
// figure out a better way after the heuristics land.
await sleep(500, "Guarantee asynchronous identifyAutofillFields is invoked");
if (rootElement.hasAttribute("test-formautofill-identified")) {
return;
}
if (!previouslyFocused) {
await new Promise(resolve => {
formFillChromeScript.addMessageListener("FormAutofillTest:FieldsIdentified", function onIdentified() {
formFillChromeScript.removeMessageListener("FormAutofillTest:FieldsIdentified", onIdentified);
resolve();
});
});
}
// In order to ensure that "markAsAutofillField" is fully executed, a short period
// of timeout is still required.
await sleep(300, "Guarantee asynchronous identifyAutofillFields is invoked");
rootElement.setAttribute("test-formautofill-identified", "true");
}
async function setInput(selector, value, userInput = false) {
const input = document.querySelector("input" + selector);
if (userInput) {
SpecialPowers.wrap(input).setUserInput(value);
} else {
input.value = value;
}
await focusAndWaitForFieldsIdentified(input);
return input;
}

View File

@ -169,6 +169,10 @@ var ParentUtils = {
Services.obs.addObserver(ParentUtils, "formautofill-storage-changed");
Services.mm.addMessageListener("FormAutofill:FieldsIdentified", () => {
sendAsyncMessage("FormAutofillTest:FieldsIdentified");
});
addMessageListener("FormAutofillTest:AddAddress", (msg) => {
ParentUtils.operateAddress("add", msg, "FormAutofillTest:AddressAdded");
});