Bug 1595154, add a test for form fillin that uses a child iframe loaded in a separate process, r=MattN

Differential Revision: https://phabricator.services.mozilla.com/D52723

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Neil Deakin 2019-12-11 13:38:13 +00:00
Родитель c93677f198
Коммит a3b79c2f38
8 изменённых файлов: 287 добавлений и 25 удалений

Просмотреть файл

@ -2,6 +2,7 @@
head = head.js head = head.js
support-files = support-files =
../fixtures/autocomplete_basic.html ../fixtures/autocomplete_basic.html
../fixtures/autocomplete_iframe.html
../fixtures/autocomplete_simple_basic.html ../fixtures/autocomplete_simple_basic.html
[browser_autocomplete_footer.js] [browser_autocomplete_footer.js]
@ -15,6 +16,7 @@ skip-if = (verify && (os == 'win' || os == 'mac'))
[browser_first_time_use_doorhanger.js] [browser_first_time_use_doorhanger.js]
skip-if = verify skip-if = verify
[browser_manageAddressesDialog.js] [browser_manageAddressesDialog.js]
[browser_remoteiframe.js]
[browser_submission_in_private_mode.js] [browser_submission_in_private_mode.js]
[browser_update_doorhanger.js] [browser_update_doorhanger.js]
skip-if = true # bug 1426981 # Bug 1445538 skip-if = true # bug 1426981 # Bug 1445538

Просмотреть файл

@ -3,20 +3,6 @@
const URL = BASE_URL + "autocomplete_basic.html"; const URL = BASE_URL + "autocomplete_basic.html";
const PRIVACY_PREF_URL = "about:preferences#privacy"; const PRIVACY_PREF_URL = "about:preferences#privacy";
async function expectWarningText(browser, expectedText) {
const {
autoCompletePopup: { richlistbox: itemsBox },
} = browser;
const warningBox = itemsBox.querySelector(
".autocomplete-richlistitem:last-child"
)._warningTextBox;
await BrowserTestUtils.waitForCondition(() => {
return warningBox.textContent == expectedText;
}, `Waiting for expected warning text: ${expectedText}, Got ${warningBox.textContent}`);
ok(true, `Got expected warning text: ${expectedText}`);
}
add_task(async function setup_storage() { add_task(async function setup_storage() {
await saveAddress(TEST_ADDRESS_2); await saveAddress(TEST_ADDRESS_2);
await saveAddress(TEST_ADDRESS_3); await saveAddress(TEST_ADDRESS_3);

Просмотреть файл

@ -0,0 +1,139 @@
/* eslint-disable mozilla/no-arbitrary-setTimeout */
"use strict";
const IFRAME_URL_PATH = BASE_URL + "autocomplete_iframe.html";
const PRIVACY_PREF_URL = "about:preferences#privacy";
// Start by adding a few addresses to storage.
add_task(async function setup_storage() {
await saveAddress(TEST_ADDRESS_2);
await saveAddress(TEST_ADDRESS_4);
await saveAddress(TEST_ADDRESS_5);
});
// Verify that form fillin works in a remote iframe, and that changing
// a field updates storage.
add_task(async function test_iframe_autocomplete() {
await SpecialPowers.pushPrefEnv({
set: [[CREDITCARDS_USED_STATUS_PREF, 0]],
});
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
IFRAME_URL_PATH,
true
);
let browser = tab.linkedBrowser;
let iframeBC = browser.browsingContext.getChildren()[1];
await openPopupForSubframe(browser, iframeBC, "#street-address");
// Highlight the first item in the list. We want to verify
// that the warning text is correct to ensure that the preview is
// performed properly.
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
await expectWarningText(browser, "Autofills address");
// Highlight and select the second item in the list
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
await expectWarningText(browser, "Also autofills organization, email");
EventUtils.synthesizeKey("VK_RETURN", {});
let promiseShown = BrowserTestUtils.waitForEvent(
PopupNotifications.panel,
"popupshown"
);
await new Promise(resolve => setTimeout(resolve, 1000));
let loadPromise = BrowserTestUtils.browserLoaded(browser, true);
await SpecialPowers.spawn(iframeBC, [], async function() {
Assert.equal(
content.document.getElementById("street-address").value,
"32 Vassar Street MIT Room 32-G524"
);
Assert.equal(content.document.getElementById("country").value, "US");
let org = content.document.getElementById("organization");
Assert.equal(org.value, "World Wide Web Consortium");
// Now, modify the organization.
org.setUserInput("Example Inc.");
await new Promise(resolve => content.setTimeout(resolve, 1000));
content.document.querySelector("input[type=submit]").click();
});
await loadPromise;
await promiseShown;
let onChanged = TestUtils.topicObserved("formautofill-storage-changed");
await clickDoorhangerButton(MAIN_BUTTON);
await onChanged;
// Check that the organization was updated properly.
let addresses = await getAddresses();
is(addresses.length, 3, "Still 1 address in storage");
is(
addresses[1].organization,
"Example Inc.",
"Verify the organization field"
);
// Fill in the details again and then clear the form from the dropdown.
await openPopupForSubframe(browser, iframeBC, "#street-address");
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
EventUtils.synthesizeKey("VK_RETURN", {});
await new Promise(resolve => setTimeout(resolve, 1000));
// Open the dropdown and select the Clear Form item.
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
EventUtils.synthesizeKey("VK_RETURN", {});
await new Promise(resolve => setTimeout(resolve, 1000));
await SpecialPowers.spawn(iframeBC, [], async function() {
Assert.equal(content.document.getElementById("street-address").value, "");
Assert.equal(content.document.getElementById("country").value, "");
Assert.equal(content.document.getElementById("organization").value, "");
});
await BrowserTestUtils.removeTab(tab);
});
// Choose preferences from the autocomplete dropdown within an iframe.
add_task(async function test_iframe_autocomplete_preferences() {
await SpecialPowers.pushPrefEnv({
set: [[CREDITCARDS_USED_STATUS_PREF, 0]],
});
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
IFRAME_URL_PATH,
true
);
let browser = tab.linkedBrowser;
let iframeBC = browser.browsingContext.getChildren()[1];
await openPopupForSubframe(browser, iframeBC, "#organization");
await expectWarningText(browser, "Also autofills address, email");
const prefTabPromise = BrowserTestUtils.waitForNewTab(
gBrowser,
PRIVACY_PREF_URL
);
// Select the preferences item.
EventUtils.synthesizeKey("VK_DOWN", {});
EventUtils.synthesizeKey("VK_DOWN", {});
EventUtils.synthesizeKey("VK_RETURN", {});
info(`expecting tab: about:preferences#privacy opened`);
const prefTab = await prefTabPromise;
info(`expecting tab: about:preferences#privacy removed`);
BrowserTestUtils.removeTab(prefTab);
await BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -6,6 +6,7 @@ support-files =
../head.js ../head.js
!/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html !/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
../../fixtures/autocomplete_creditcard_basic.html ../../fixtures/autocomplete_creditcard_basic.html
../../fixtures/autocomplete_creditcard_iframe.html
head_cc.js head_cc.js
[browser_creditCard_doorhanger.js] [browser_creditCard_doorhanger.js]

Просмотреть файл

@ -149,6 +149,61 @@ add_task(async function test_submit_untouched_creditCard_form() {
await removeAllRecords(); await removeAllRecords();
}); });
add_task(async function test_submit_untouched_creditCard_form_iframe() {
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
todo(
OSKeyStoreTestUtils.canTestOSKeyStoreLogin(),
"Cannot test OS key store login on official builds."
);
return;
}
await SpecialPowers.pushPrefEnv({
set: [[CREDITCARDS_USED_STATUS_PREF, 0]],
});
await saveCreditCard(TEST_CREDIT_CARD_1);
let creditCards = await getCreditCards();
is(creditCards.length, 1, "1 credit card in storage");
let osKeyStoreLoginShown = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(true);
let onUsed = TestUtils.topicObserved(
"formautofill-storage-changed",
(subject, data) => data == "notifyUsed"
);
await BrowserTestUtils.withNewTab(
{ gBrowser, url: CREDITCARD_FORM_IFRAME_URL },
async function(browser) {
let iframeBC = browser.browsingContext.getChildren()[0];
await openPopupForSubframe(browser, iframeBC, "form #cc-name");
EventUtils.synthesizeKey("VK_DOWN", {});
EventUtils.synthesizeKey("VK_RETURN", {});
await osKeyStoreLoginShown;
await SpecialPowers.spawn(iframeBC, [], async function() {
let form = content.document.getElementById("form");
// Wait 1000ms before submission to make sure the input value applied
await new Promise(resolve => content.setTimeout(resolve, 1000));
form.querySelector("input[type=submit]").click();
});
await sleep(1000);
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
}
);
await onUsed;
creditCards = await getCreditCards();
is(creditCards.length, 1, "Still 1 credit card");
is(creditCards[0].timesUsed, 1, "timesUsed field set to 1");
is(
SpecialPowers.getIntPref(CREDITCARDS_USED_STATUS_PREF),
3,
"User has used autofill"
);
SpecialPowers.clearUserPref(CREDITCARDS_USED_STATUS_PREF);
await removeAllRecords();
});
add_task(async function test_submit_changed_subset_creditCard_form() { add_task(async function test_submit_changed_subset_creditCard_form() {
await SpecialPowers.pushPrefEnv({ await SpecialPowers.pushPrefEnv({
set: [[CREDITCARDS_USED_STATUS_PREF, 0]], set: [[CREDITCARDS_USED_STATUS_PREF, 0]],

Просмотреть файл

@ -1,15 +1,15 @@
/* exported MANAGE_ADDRESSES_DIALOG_URL, MANAGE_CREDIT_CARDS_DIALOG_URL, EDIT_ADDRESS_DIALOG_URL, EDIT_CREDIT_CARD_DIALOG_URL, /* exported MANAGE_ADDRESSES_DIALOG_URL, MANAGE_CREDIT_CARDS_DIALOG_URL, EDIT_ADDRESS_DIALOG_URL, EDIT_CREDIT_CARD_DIALOG_URL,
BASE_URL, TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3, TEST_ADDRESS_4, TEST_ADDRESS_5, TEST_ADDRESS_CA_1, TEST_ADDRESS_DE_1, BASE_URL, TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3, TEST_ADDRESS_4, TEST_ADDRESS_5, TEST_ADDRESS_CA_1, TEST_ADDRESS_DE_1,
TEST_ADDRESS_IE_1, TEST_ADDRESS_IE_1,
TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2, TEST_CREDIT_CARD_3, FORM_URL, CREDITCARD_FORM_URL, TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2, TEST_CREDIT_CARD_3, FORM_URL, CREDITCARD_FORM_URL, CREDITCARD_FORM_IFRAME_URL
FTU_PREF, ENABLED_AUTOFILL_ADDRESSES_PREF, AUTOFILL_CREDITCARDS_AVAILABLE_PREF, ENABLED_AUTOFILL_CREDITCARDS_PREF, FTU_PREF, ENABLED_AUTOFILL_ADDRESSES_PREF, AUTOFILL_CREDITCARDS_AVAILABLE_PREF, ENABLED_AUTOFILL_CREDITCARDS_PREF,
SUPPORTED_COUNTRIES_PREF, SUPPORTED_COUNTRIES_PREF,
SYNC_USERNAME_PREF, SYNC_ADDRESSES_PREF, SYNC_CREDITCARDS_PREF, SYNC_CREDITCARDS_AVAILABLE_PREF, CREDITCARDS_USED_STATUS_PREF, SYNC_USERNAME_PREF, SYNC_ADDRESSES_PREF, SYNC_CREDITCARDS_PREF, SYNC_CREDITCARDS_AVAILABLE_PREF, CREDITCARDS_USED_STATUS_PREF,
DEFAULT_REGION_PREF, DEFAULT_REGION_PREF,
sleep, expectPopupOpen, openPopupOn, expectPopupClose, closePopup, clickDoorhangerButton, sleep, expectPopupOpen, openPopupOn, openPopupForSubframe, expectPopupClose, closePopup, closePopupForSubframe,
getAddresses, saveAddress, removeAddresses, saveCreditCard, clickDoorhangerButton, getAddresses, saveAddress, removeAddresses, saveCreditCard,
getDisplayedPopupItems, getDoorhangerCheckbox, getDisplayedPopupItems, getDoorhangerCheckbox,
getNotification, getDoorhangerButton, removeAllRecords, testDialog */ getNotification, getDoorhangerButton, removeAllRecords, expectWarningText, testDialog */
"use strict"; "use strict";
@ -32,6 +32,10 @@ const CREDITCARD_FORM_URL =
"https://example.org" + "https://example.org" +
HTTP_TEST_PATH + HTTP_TEST_PATH +
"creditCard/autocomplete_creditcard_basic.html"; "creditCard/autocomplete_creditcard_basic.html";
const CREDITCARD_FORM_IFRAME_URL =
"https://example.org" +
HTTP_TEST_PATH +
"creditCard/autocomplete_creditcard_iframe.html";
const FTU_PREF = "extensions.formautofill.firstTimeUse"; const FTU_PREF = "extensions.formautofill.firstTimeUse";
const CREDITCARDS_USED_STATUS_PREF = "extensions.formautofill.creditCards.used"; const CREDITCARDS_USED_STATUS_PREF = "extensions.formautofill.creditCards.used";
@ -175,7 +179,7 @@ async function sleep(ms = 500) {
await new Promise(resolve => setTimeout(resolve, ms)); await new Promise(resolve => setTimeout(resolve, ms));
} }
async function focusAndWaitForFieldsIdentified(browser, selector) { async function focusAndWaitForFieldsIdentified(browserOrContext, selector) {
info("expecting the target input being focused and identified"); info("expecting the target input being focused and identified");
/* eslint no-shadow: ["error", { "allow": ["selector", "previouslyFocused", "previouslyIdentified"] }] */ /* eslint no-shadow: ["error", { "allow": ["selector", "previouslyFocused", "previouslyIdentified"] }] */
@ -197,10 +201,10 @@ async function focusAndWaitForFieldsIdentified(browser, selector) {
FormAutofillParent.addMessageObserver(fieldsIdentifiedObserver); FormAutofillParent.addMessageObserver(fieldsIdentifiedObserver);
}); });
const { previouslyFocused, previouslyIdentified } = await ContentTask.spawn( const { previouslyFocused, previouslyIdentified } = await SpecialPowers.spawn(
browser, browserOrContext,
{ selector }, [selector],
async function({ selector }) { async function(selector) {
const { FormLikeFactory } = ChromeUtils.import( const { FormLikeFactory } = ChromeUtils.import(
"resource://gre/modules/FormLikeFactory.jsm" "resource://gre/modules/FormLikeFactory.jsm"
); );
@ -225,6 +229,20 @@ async function focusAndWaitForFieldsIdentified(browser, selector) {
info("!previouslyFocused"); info("!previouslyFocused");
} }
// If a browsing context was supplied, focus its parent frame as well.
if (
browserOrContext instanceof BrowsingContext &&
browserOrContext.parent != browserOrContext
) {
await SpecialPowers.spawn(
browserOrContext.parent,
[browserOrContext],
async function(browsingContext) {
browsingContext.embedderElement.focus();
}
);
}
if (previouslyIdentified) { if (previouslyIdentified) {
info("previouslyIdentified"); info("previouslyIdentified");
return; return;
@ -236,7 +254,7 @@ async function focusAndWaitForFieldsIdentified(browser, selector) {
FormAutofillParent.removeMessageObserver(fieldsIdentifiedObserver); FormAutofillParent.removeMessageObserver(fieldsIdentifiedObserver);
await sleep(); await sleep();
await ContentTask.spawn(browser, {}, async function() { await SpecialPowers.spawn(browserOrContext, [], async function() {
const { FormLikeFactory } = ChromeUtils.import( const { FormLikeFactory } = ChromeUtils.import(
"resource://gre/modules/FormLikeFactory.jsm" "resource://gre/modules/FormLikeFactory.jsm"
); );
@ -277,6 +295,14 @@ async function openPopupOn(browser, selector) {
await expectPopupOpen(browser); await expectPopupOpen(browser);
} }
async function openPopupForSubframe(browser, frameBrowsingContext, selector) {
await SimpleTest.promiseFocus(browser);
await focusAndWaitForFieldsIdentified(frameBrowsingContext, selector);
info("openPopupOn: before VK_DOWN");
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, frameBrowsingContext);
await expectPopupOpen(browser);
}
async function expectPopupClose(browser) { async function expectPopupClose(browser) {
await BrowserTestUtils.waitForCondition( await BrowserTestUtils.waitForCondition(
() => !browser.autoCompletePopup.popupOpen, () => !browser.autoCompletePopup.popupOpen,
@ -285,7 +311,15 @@ async function expectPopupClose(browser) {
} }
async function closePopup(browser) { async function closePopup(browser) {
await ContentTask.spawn(browser, {}, async function() { await SpecialPowers.spawn(browser, [], async function() {
content.document.activeElement.blur();
});
await expectPopupClose(browser);
}
async function closePopupForSubframe(browser, frameBrowsingContext) {
await SpecialPowers.spawn(frameBrowsingContext, [], async function() {
content.document.activeElement.blur(); content.document.activeElement.blur();
}); });
@ -415,6 +449,26 @@ async function waitForFocusAndFormReady(win) {
]); ]);
} }
// Verify that the warning in the autocomplete popup has the expected text.
async function expectWarningText(browser, expectedText) {
const {
autoCompletePopup: { richlistbox: itemsBox },
} = browser;
let warningBox = itemsBox.querySelector(
".autocomplete-richlistitem:last-child"
);
while (warningBox.collapsed) {
warningBox = warningBox.previousSibling;
}
warningBox = warningBox._warningTextBox;
await BrowserTestUtils.waitForCondition(() => {
return warningBox.textContent == expectedText;
}, `Waiting for expected warning text: ${expectedText}, Got ${warningBox.textContent}`);
ok(true, `Got expected warning text: ${expectedText}`);
}
async function testDialog(url, testFn, arg = undefined) { async function testDialog(url, testFn, arg = undefined) {
// Skip this step for test cards that lack an encrypted // Skip this step for test cards that lack an encrypted
// number since they will fail to decrypt. // number since they will fail to decrypt.

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Form Autofill Credit Card With Remote IFrame Demo Page</title>
</head>
<body>
<iframe src="https://test1.example.com:443/browser/browser/extensions/formautofill/test/browser/creditCard/autocomplete_creditcard_basic.html" width="400" height="400">
</iframe>
</body>
</html>

Просмотреть файл

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Form Autofill With Remote IFrame Demo Page</title>
</head>
<body>
<iframe id="unused" src="data:text/html,<body>Just here to ensure code doesn't always pick the first child iframe.</body>"></iframe>
<iframe src="https://test1.example.com:443/browser/browser/extensions/formautofill/test/browser/autocomplete_basic.html" width="400" height="400">
</iframe>
</body>
</html>