Bug 1505141 - Test that address fields hidden from edit forms aren't blanked unnecessarily. r=jaws
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Wed, 21 Nov 2018 00:43:46 +0000
changeset 503928 5128dd79f222e3623c2392d83b7124f7e79db32d
parent 503927 4f693fc02c24ea7c3e66064ff07b9e50733ee4c4
child 503929 b42cd879741d9135b2681e355db070922473f0fe
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1505141
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1505141 - Test that address fields hidden from edit forms aren't blanked unnecessarily. r=jaws Depends on D12190 Differential Revision: https://phabricator.services.mozilla.com/D12191
browser/components/payments/res/components/address-option.js
browser/components/payments/test/browser/browser.ini
browser/components/payments/test/browser/browser_address_edit.js
browser/components/payments/test/browser/browser_address_edit_hidden_fields.js
browser/components/payments/test/browser/head.js
browser/components/payments/test/mochitest/test_address_form.html
--- a/browser/components/payments/res/components/address-option.js
+++ b/browser/components/payments/res/components/address-option.js
@@ -26,16 +26,17 @@ import RichOption from "./rich-option.js
  * Attribute names follow FormAutofillStorage.jsm.
  */
 
 export default class AddressOption extends ObservedPropertiesMixin(RichOption) {
   static get recordAttributes() {
     return [
       "address-level1",
       "address-level2",
+      "address-level3",
       "country",
       "email",
       "guid",
       "name",
       "organization",
       "postal-code",
       "street-address",
       "tel",
--- a/browser/components/payments/test/browser/browser.ini
+++ b/browser/components/payments/test/browser/browser.ini
@@ -5,16 +5,17 @@ prefs =
   dom.payments.request.enabled=true
   extensions.formautofill.creditCards.available=true
 skip-if = !e10s # Bug 1365964 - Payment Request isn't implemented for non-e10s
 support-files =
   blank_page.html
 
 [browser_address_edit.js]
 skip-if = verify && debug && os == 'mac'
+[browser_address_edit_hidden_fields.js]
 [browser_card_edit.js]
 skip-if = debug && (os == 'mac' || os == 'linux') # bug 1465673
 [browser_change_shipping.js]
 [browser_dropdowns.js]
 [browser_host_name.js]
 [browser_onboarding_wizard.js]
 [browser_openPreferences.js]
 [browser_payerRequestedFields.js]
--- a/browser/components/payments/test/browser/browser_address_edit.js
+++ b/browser/components/payments/test/browser/browser_address_edit.js
@@ -591,155 +591,16 @@ add_task(async function test_private_per
        "Check street-address in response");
     is(responseAddress.country, addressToAdd.country, "Check country in response");
   });
   // verify formautofill store doesnt have the new temp addresses
   is((await formAutofillStorage.addresses.getAll()).length, 1,
      "Original 1 stored address at end of test");
 });
 
-add_task(async function test_hiddenFieldNotSaved() {
-  await setup();
-
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    let newAddress = Object.assign({}, PTU.Addresses.TimBL);
-    newAddress["given-name"] = "hiddenFields";
-
-    let shippingAddressChangePromise = ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    let options = {
-      expectPersist: true,
-      isEditing: false,
-    };
-    await navigateToAddAddressPage(frame);
-    info("navigated to add address page");
-    await fillInShippingAddressForm(frame, newAddress, options);
-    info("filled in TimBL address");
-
-    await spawnPaymentDialogTask(frame, async (args) => {
-      let countryField = content.document.getElementById("country");
-      await content.fillField(countryField, "DE");
-    });
-    info("changed selected country to Germany");
-
-    await submitAddressForm(frame, null, options);
-    await shippingAddressChangePromise;
-    info("got shippingaddresschange event");
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(savedAddresses).length, 2, "2 saved addresses");
-      let savedAddress = Object.values(savedAddresses)
-                               .find(address => address["given-name"] == "hiddenFields");
-      ok(savedAddress, "found the saved address");
-      is(savedAddress.country, "DE", "check country");
-      is(savedAddress["address-level2"], PTU.Addresses.TimBL["address-level2"],
-         "check address-level2");
-      is(savedAddress["address-level1"], undefined, "address-level1 should not be saved");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
-add_task(async function test_hiddenFieldRemovedWhenCountryChanged() {
-  await setup();
-
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    let shippingAddressChangePromise = ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    await spawnPaymentDialogTask(frame, async (args) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let picker = content.document
-                     .querySelector("address-picker[selected-state-key='selectedShippingAddress']");
-      Cu.waiveXrays(picker).dropdown.popupBox.focus();
-      EventUtils.synthesizeKey(PTU.Addresses.TimBL["given-name"], {}, content.window);
-
-      let editLink = content.document.querySelector("address-picker .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let countryField = content.document.getElementById("country");
-      await content.fillField(countryField, "DE");
-      info("changed selected country to Germany");
-    });
-
-    let options = {
-      isEditing: true,
-    };
-    await submitAddressForm(frame, null, options);
-    await shippingAddressChangePromise;
-    info("got shippingaddresschange event");
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(savedAddresses).length, 1, "1 saved address");
-      let savedAddress = Object.values(savedAddresses)[0];
-      is(savedAddress.country, "DE", "check country");
-      is(savedAddress["address-level2"], PTU.Addresses.TimBL["address-level2"],
-         "check address-level2");
-      is(savedAddress["address-level1"], undefined, "address-level1 should not be saved");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
 add_task(async function test_countrySpecificFieldsGetRequiredness() {
   await setup();
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: BLANK_PAGE_URL,
   }, async browser => {
     let {win, frame} =
       await setupPaymentDialog(browser, {
copy from browser/components/payments/test/browser/browser_address_edit.js
copy to browser/components/payments/test/browser/browser_address_edit_hidden_fields.js
--- a/browser/components/payments/test/browser/browser_address_edit.js
+++ b/browser/components/payments/test/browser/browser_address_edit_hidden_fields.js
@@ -1,9 +1,11 @@
-/* eslint-disable no-shadow */
+/**
+ * Test saving/updating address records with fields sometimes not visible to the user.
+ */
 
 "use strict";
 
 async function setup() {
   await setupFormAutofillStorage();
   await cleanupFormAutofillStorage();
   // add an address and card to avoid the FTU sequence
   let prefilledGuids = await addSampleAddressesAndBasicCard(
@@ -12,594 +14,16 @@ async function setup() {
   info("associating the card with the billing address");
   await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
     billingAddressGUID: prefilledGuids.address1GUID,
   }, true);
 
   return prefilledGuids;
 }
 
-/*
- * Test that we can correctly add an address and elect for it to be saved or temporary
- */
-add_task(async function test_add_link() {
-  let prefilledGuids = await setup();
-
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    info("setup got prefilledGuids: " + JSON.stringify(prefilledGuids));
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {tempAddresses, savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(tempAddresses).length, 0, "No temporary addresses at the start of test");
-      is(Object.keys(savedAddresses).length, 1, "1 saved address at the start of test");
-    });
-
-    let testOptions = [
-      { setPersistCheckedValue: true, expectPersist: true },
-      { setPersistCheckedValue: false, expectPersist: false },
-    ];
-    let newAddress = Object.assign({}, PTU.Addresses.TimBL2);
-    // Emails aren't part of shipping addresses
-    delete newAddress.email;
-
-    for (let options of testOptions) {
-      let shippingAddressChangePromise = ContentTask.spawn(browser, {
-        eventName: "shippingaddresschange",
-      }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-      await manuallyAddShippingAddress(frame, newAddress, options);
-      await shippingAddressChangePromise;
-      info("got shippingaddresschange event");
-
-      await spawnPaymentDialogTask(frame, async ({address, options, prefilledGuids}) => {
-        let {
-          PaymentTestUtils: PTU,
-        } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-        let newAddresses = await PTU.DialogContentUtils.waitForState(content, (state) => {
-          return state.tempAddresses && state.savedAddresses;
-        });
-        let colnName = options.expectPersist ? "savedAddresses" : "tempAddresses";
-        // remove any pre-filled entries
-        delete newAddresses[colnName][prefilledGuids.address1GUID];
-
-        let addressGUIDs = Object.keys(newAddresses[colnName]);
-        is(addressGUIDs.length, 1, "Check there is one address");
-        let resultAddress = newAddresses[colnName][addressGUIDs[0]];
-        for (let [key, val] of Object.entries(address)) {
-          is(resultAddress[key], val, "Check " + key);
-        }
-      }, {address: newAddress, options, prefilledGuids});
-    }
-
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
-add_task(async function test_edit_link() {
-  let prefilledGuids = await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    let shippingAddressChangePromise = ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    const EXPECTED_ADDRESS = {
-      "given-name": "Jaws",
-      "family-name": "swaJ",
-      "organization": "aliizoM",
-    };
-
-    info("setup got prefilledGuids: " + JSON.stringify(prefilledGuids));
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {tempAddresses, savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(tempAddresses).length, 0, "No temporary addresses at the start of test");
-      is(Object.keys(savedAddresses).length, 1, "1 saved address at the start of test");
-
-      let picker = content.document
-                     .querySelector("address-picker[selected-state-key='selectedShippingAddress']");
-      Cu.waiveXrays(picker).dropdown.popupBox.focus();
-      EventUtils.synthesizeKey(PTU.Addresses.TimBL["given-name"], {}, content.window);
-
-      let editLink = content.document.querySelector("address-picker .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let title = content.document.querySelector("address-form h2");
-      is(title.textContent, "Edit Shipping Address", "Page title should be set");
-
-      let saveButton = content.document.querySelector("address-form .save-button");
-      is(saveButton.textContent, "Update", "Save button has the correct label");
-    });
-
-    let editOptions = {
-      checkboxSelector: "#address-page .persist-checkbox",
-      isEditing: true,
-      expectPersist: true,
-    };
-    await fillInShippingAddressForm(frame, EXPECTED_ADDRESS, editOptions);
-    await verifyPersistCheckbox(frame, editOptions);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, editOptions);
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        let addresses = Object.entries(state.savedAddresses);
-        return addresses.length == 1 &&
-               addresses[0][1]["given-name"] == address["given-name"];
-      }, "Check address was edited");
-
-      let addressGUIDs = Object.keys(state.savedAddresses);
-      is(addressGUIDs.length, 1, "Check there is still one address");
-      let savedAddress = state.savedAddresses[addressGUIDs[0]];
-      for (let [key, val] of Object.entries(address)) {
-        is(savedAddress[key], val, "Check updated " + key);
-      }
-      ok(savedAddress.guid, "Address has a guid");
-      ok(savedAddress.name, "Address has a name");
-      ok(savedAddress.name.includes(address["given-name"]) &&
-         savedAddress.name.includes(address["family-name"]), "Address.name was computed");
-
-      state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "payment-summary";
-      }, "Switched back to payment-summary");
-    }, EXPECTED_ADDRESS);
-
-    await shippingAddressChangePromise;
-    info("got shippingaddresschange event");
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
-add_task(async function test_add_payer_contact_name_email_link() {
-  await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestPayerNameAndEmail,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    const EXPECTED_ADDRESS = {
-      "given-name": "Deraj",
-      "family-name": "Niew",
-      "email": "test@example.com",
-    };
-
-    const addOptions = {
-      addLinkSelector: "address-picker.payer-related .add-link",
-      checkboxSelector: "#address-page .persist-checkbox",
-      initialPageId: "payment-summary",
-      expectPersist: true,
-    };
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {tempAddresses, savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(tempAddresses).length, 0, "No temporary addresses at the start of test");
-      is(Object.keys(savedAddresses).length, 1, "1 saved address at the start of test");
-    });
-
-    await navigateToAddAddressPage(frame, addOptions);
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let title = content.document.querySelector("address-form h2");
-      is(title.textContent, "Add Payer Contact", "Page title should be set");
-
-      let saveButton = content.document.querySelector("address-form .save-button");
-      is(saveButton.textContent, "Next", "Save button has the correct label");
-
-      info("check that non-payer requested fields are hidden");
-      for (let selector of ["#organization", "#tel"]) {
-        let element = content.document.querySelector(selector);
-        ok(content.isHidden(element), selector + " should be hidden");
-      }
-    });
-
-    await fillInPayerAddressForm(frame, EXPECTED_ADDRESS, addOptions);
-    await verifyPersistCheckbox(frame, addOptions);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, addOptions);
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-
-      let addressGUIDs = Object.keys(savedAddresses);
-      is(addressGUIDs.length, 2, "Check there are now 2 addresses");
-      let savedAddress = savedAddresses[addressGUIDs[1]];
-      for (let [key, val] of Object.entries(address)) {
-        is(savedAddress[key], val, "Check " + key);
-      }
-      ok(savedAddress.guid, "Address has a guid");
-      ok(savedAddress.name, "Address has a name");
-      ok(savedAddress.name.includes(address["given-name"]) &&
-         savedAddress.name.includes(address["family-name"]), "Address.name was computed");
-    }, EXPECTED_ADDRESS);
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-add_task(async function test_edit_payer_contact_name_email_phone_link() {
-  await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestPayerNameEmailAndPhone,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    const EXPECTED_ADDRESS = {
-      "given-name": "Deraj",
-      "family-name": "Niew",
-      "email": "test@example.com",
-      "tel": "+15555551212",
-    };
-    const editOptions = {
-      checkboxSelector: "#address-page .persist-checkbox",
-      expectPersist: true,
-      isEditing: true,
-    };
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return Object.keys(state.savedAddresses).length == 1;
-      }, "One saved addresses when starting test");
-
-      let editLink =
-        content.document.querySelector("address-picker.payer-related .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let title = content.document.querySelector("address-form h2");
-      is(title.textContent, "Edit Payer Contact", "Page title should be set");
-
-      let saveButton = content.document.querySelector("address-form .save-button");
-      is(saveButton.textContent, "Update", "Save button has the correct label");
-
-      info("check that non-payer requested fields are hidden");
-      let formElements =
-        content.document.querySelectorAll("address-form :-moz-any(input, select, textarea");
-      let allowedFields = ["given-name", "additional-name", "family-name", "email", "tel"];
-      for (let element of formElements) {
-        let shouldBeVisible = allowedFields.includes(element.id);
-        if (shouldBeVisible) {
-          ok(content.isVisible(element), element.id + " should be visible");
-        } else {
-          ok(content.isHidden(element), element.id + " should be hidden");
-        }
-      }
-
-      info("overwriting field values");
-      for (let [key, val] of Object.entries(address)) {
-        let field = content.document.getElementById(key);
-        field.value = val + "1";
-        ok(!field.disabled, `Field #${key} shouldn't be disabled`);
-      }
-    }, EXPECTED_ADDRESS);
-
-    await verifyPersistCheckbox(frame, editOptions);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, editOptions);
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        let addresses = Object.entries(state.savedAddresses);
-        return addresses.length == 1 &&
-               addresses[0][1]["given-name"] == address["given-name"] + "1";
-      }, "Check address was edited");
-
-      let addressGUIDs = Object.keys(state.savedAddresses);
-      is(addressGUIDs.length, 1, "Check there is still one address");
-      let savedAddress = state.savedAddresses[addressGUIDs[0]];
-      for (let [key, val] of Object.entries(address)) {
-        is(savedAddress[key], val + "1", "Check updated " + key);
-      }
-      ok(savedAddress.guid, "Address has a guid");
-      ok(savedAddress.name, "Address has a name");
-      ok(savedAddress.name.includes(address["given-name"]) &&
-         savedAddress.name.includes(address["family-name"]), "Address.name was computed");
-    }, EXPECTED_ADDRESS);
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-add_task(async function test_shipping_address_picker() {
-  await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    await spawnPaymentDialogTask(frame, async function test_picker_option_label(address) {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-      ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return Object.keys(state.savedAddresses).length == 1;
-      }, "One saved addresses when starting test");
-      let savedAddress = Object.values(state.savedAddresses)[0];
-
-      let selector = "address-picker[selected-state-key='selectedShippingAddress']";
-      let picker = content.document.querySelector(selector);
-      let option = Cu.waiveXrays(picker).dropdown.popupBox.children[0];
-      is(option.textContent,
-         FormAutofillUtils.getAddressLabel(savedAddress, null),
-         "Shows correct shipping option label");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-add_task(async function test_payer_address_picker() {
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestPayerNameEmailAndPhone,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    await spawnPaymentDialogTask(frame, async function test_picker_option_label(address) {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-      ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return Object.keys(state.savedAddresses).length == 1;
-      }, "One saved addresses when starting test");
-      let savedAddress = Object.values(state.savedAddresses)[0];
-
-      let selector = "address-picker[selected-state-key='selectedPayerAddress']";
-      let picker = content.document.querySelector(selector);
-      let option = Cu.waiveXrays(picker).dropdown.popupBox.children[0];
-      is(option.textContent.includes("32 Vassar Street"), false,
-         "Payer option label does not contain street address");
-      is(option.textContent,
-         FormAutofillUtils.getAddressLabel(savedAddress, "name tel email"),
-         "Shows correct payer option label");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-/*
- * Test that we can correctly add an address from a private window
- */
-add_task(async function test_private_persist_addresses() {
-  if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
-    todo(false, "Cannot test OS key store login on official builds.");
-    return;
-  }
-  let prefilledGuids = await setup();
-
-  is((await formAutofillStorage.addresses.getAll()).length, 1,
-     "Setup results in 1 stored address at start of test");
-
-  await withNewTabInPrivateWindow({
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    info("in new tab w. private window");
-    let {frame} =
-      // setupPaymentDialog from a private window.
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-    info("/setupPaymentDialog");
-
-    let addressToAdd = Object.assign({}, PTU.Addresses.Temp);
-    // Emails aren't part of shipping addresses
-    delete addressToAdd.email;
-    const addOptions = {
-      checkboxSelector: "#address-page .persist-checkbox",
-      expectPersist: false,
-      isPrivate: true,
-    };
-
-    await navigateToAddAddressPage(frame);
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.getCurrentState(content);
-      info("on address-page and state.isPrivate: " + state.isPrivate);
-      ok(state.isPrivate,
-         "isPrivate flag is set when paymentrequest is shown in a private session");
-    });
-
-    info("wait for initialAddresses");
-    let initialAddresses =
-      await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingAddresses);
-    is(initialAddresses.options.length, 1,
-       "Got expected number of pre-filled shipping addresses");
-
-    await fillInShippingAddressForm(frame, addressToAdd, addOptions);
-    await verifyPersistCheckbox(frame, addOptions);
-    await submitAddressForm(frame, addressToAdd, addOptions);
-
-    let shippingAddresses =
-      await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingAddresses);
-    info("shippingAddresses", shippingAddresses);
-    let addressOptions = shippingAddresses.options;
-    // expect the prefilled address + the new temporary address
-    is(addressOptions.length, 2, "The picker has the expected number of address options");
-    let tempAddressOption = addressOptions.find(addr => addr.guid != prefilledGuids.address1GUID);
-    let tempAddressGuid = tempAddressOption.guid;
-    // select the new address
-    await spawnPaymentDialogTask(frame,
-                                 PTU.DialogContentTasks.selectShippingAddressByGuid,
-                                 tempAddressGuid);
-
-    info("awaiting the shippingaddresschange event");
-    await ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    await spawnPaymentDialogTask(frame, async (args) => {
-      let {address, tempAddressGuid} = args;
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.selectedShippingAddress == tempAddressGuid;
-      }, "Check the temp address is the selectedShippingAddress");
-
-      let addressGUIDs = Object.keys(state.tempAddresses);
-      is(addressGUIDs.length, 1, "Check there is one address");
-
-      is(addressGUIDs[0], tempAddressGuid, "guid from state and picker options match");
-      let tempAddress = state.tempAddresses[tempAddressGuid];
-      for (let [key, val] of Object.entries(address)) {
-        is(tempAddress[key], val, "Check field " + key);
-      }
-      ok(tempAddress.guid, "Address has a guid");
-      ok(tempAddress.name, "Address has a name");
-      ok(tempAddress.name.includes(address["given-name"]) &&
-         tempAddress.name.includes(address["family-name"]), "Address.name was computed");
-    }, {address: addressToAdd, tempAddressGuid});
-
-    await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.setSecurityCode, {
-      securityCode: "123",
-    });
-
-    info("clicking pay");
-    await loginAndCompletePayment(frame);
-
-    // Add a handler to complete the payment above.
-    info("acknowledging the completion from the merchant page");
-    let result = await ContentTask.spawn(browser, {}, PTU.ContentTasks.addCompletionHandler);
-
-    // Verify response has the expected properties
-    info("response: " + JSON.stringify(result.response));
-    let responseAddress = result.response.shippingAddress;
-    ok(responseAddress, "response should contain the shippingAddress");
-    ok(responseAddress.recipient.includes(addressToAdd["given-name"]),
-       "Check given-name matches recipient in response");
-    ok(responseAddress.recipient.includes(addressToAdd["family-name"]),
-       "Check family-name matches recipient in response");
-    is(responseAddress.addressLine[0], addressToAdd["street-address"],
-       "Check street-address in response");
-    is(responseAddress.country, addressToAdd.country, "Check country in response");
-  });
-  // verify formautofill store doesnt have the new temp addresses
-  is((await formAutofillStorage.addresses.getAll()).length, 1,
-     "Original 1 stored address at end of test");
-});
 
 add_task(async function test_hiddenFieldNotSaved() {
   await setup();
 
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: BLANK_PAGE_URL,
   }, async browser => {
@@ -730,85 +154,185 @@ add_task(async function test_hiddenField
     info("clicking cancel");
     spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
 
     await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
   });
   await cleanupFormAutofillStorage();
 });
 
-add_task(async function test_countrySpecificFieldsGetRequiredness() {
-  await setup();
+add_task(async function test_hiddenNonShippingFieldsPreservedUponEdit() {
+  await setupFormAutofillStorage();
+  await cleanupFormAutofillStorage();
+  // add a Brazilian address (since it uses all fields) and card to avoid the FTU sequence
+  let prefilledGuids = await addSampleAddressesAndBasicCard(
+    [PTU.Addresses.TimBR], [PTU.BasicCards.JohnDoe]);
+  let expected = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: BLANK_PAGE_URL,
   }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    await navigateToAddAddressPage(frame);
+    let {win, frame} = await setupPaymentDialog(browser, {
+      methodData: [PTU.MethodData.basicCard],
+      details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
+      options: PTU.Options.requestShippingOption,
+      merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+    });
 
-    const EXPECTED_ADDRESS = {
-      "country": "MO",
-      "given-name": "First",
-      "family-name": "Last",
-      "street-address": "12345 FooFoo Bar",
-    };
-    await fillInShippingAddressForm(frame, EXPECTED_ADDRESS);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, {expectPersist: true});
+    await selectPaymentDialogShippingAddressByCountry(frame, "BR");
 
-    await navigateToAddAddressPage(frame);
-
-    await selectPaymentDialogShippingAddressByCountry(frame, "MO");
+    await navigateToAddAddressPage(frame, {
+      addLinkSelector: "address-picker[selected-state-key=\"selectedShippingAddress\"] .edit-link",
+      initialPageId: "payment-summary",
+    });
 
     await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let editLink = content.document.querySelector("address-picker .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let provinceField = content.document.getElementById("address-level1");
-      let provinceContainer = provinceField.parentNode;
-      is(provinceContainer.style.display, "none", "Province should be hidden for Macau");
+      let givenNameField = content.document.querySelector(
+        "address-form #given-name"
+      );
+      await content.fillField(givenNameField, "Timothy-edit");
+    });
 
-      let countryField = content.document.getElementById("country");
-      await content.fillField(countryField, "CA");
-      info("changed selected country to Canada");
-
-      isnot(provinceContainer.style.display, "none", "Province should be visible for Canada");
-      ok(provinceContainer.hasAttribute("required"),
-         "Province container should have required attribute");
-      let provinceSpan = provinceContainer.querySelector("span");
-      is(provinceSpan.getAttribute("fieldRequiredSymbol"), "*",
-         "Province span should have asterisk as fieldRequiredSymbol");
-      is(content.window.getComputedStyle(provinceSpan, "::after").content,
-         "attr(fieldRequiredSymbol)",
-         "Asterisk should be on Province");
-
-      let addressBackButton = content.document.querySelector("address-form .back-button");
-      addressBackButton.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "payment-summary";
-      }, "Switched back to payment-summary");
-    });
+    let options = {
+      isEditing: true,
+    };
+    await submitAddressForm(frame, null, options);
 
     info("clicking cancel");
     spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
 
     await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
   });
+
+  Object.assign(expected, PTU.Addresses.TimBR, {
+    "given-name": "Timothy-edit",
+    "name": "Timothy-edit João Berners-Lee",
+  });
+  let actual = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+  isnot(actual.email, "", "Check email isn't empty");
+  // timeLastModified changes and isn't relevant
+  delete actual.timeLastModified;
+  delete expected.timeLastModified;
+  SimpleTest.isDeeply(actual, expected, "Check profile didn't lose fields");
+
   await cleanupFormAutofillStorage();
 });
+
+add_task(async function test_hiddenNonPayerFieldsPreservedUponEdit() {
+  await setupFormAutofillStorage();
+  await cleanupFormAutofillStorage();
+  // add a Brazilian address (since it uses all fields) and card to avoid the FTU sequence
+  let prefilledGuids = await addSampleAddressesAndBasicCard(
+    [PTU.Addresses.TimBR], [PTU.BasicCards.JohnDoe]);
+  let expected = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: BLANK_PAGE_URL,
+  }, async browser => {
+    let {win, frame} = await setupPaymentDialog(browser, {
+      methodData: [PTU.MethodData.basicCard],
+      details: Object.assign({}, PTU.Details.total2USD),
+      options: {
+        requestPayerEmail: true,
+      },
+      merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+    });
+
+    await navigateToAddAddressPage(frame, {
+      addLinkSelector: "address-picker[selected-state-key=\"selectedPayerAddress\"] .edit-link",
+      initialPageId: "payment-summary",
+    });
+
+    info("Change the email address");
+    await spawnPaymentDialogTask(frame, `async () => {
+      let emailField = content.document.querySelector("address-form #email");
+      await content.fillField(emailField, "new@example.com");
+    }`);
+
+    let options = {
+      isEditing: true,
+    };
+    await submitAddressForm(frame, null, options);
+
+    info("clicking cancel");
+    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
+
+    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
+  });
+
+  Object.assign(expected, PTU.Addresses.TimBR, {
+    email: "new@example.com",
+  });
+  let actual = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+  // timeLastModified changes and isn't relevant
+  delete actual.timeLastModified;
+  delete expected.timeLastModified;
+  SimpleTest.isDeeply(actual, expected, "Check profile didn't lose fields and change was made");
+
+  await cleanupFormAutofillStorage();
+});
+
+add_task(async function test_hiddenNonBillingAddressFieldsPreservedUponEdit() {
+  await setupFormAutofillStorage();
+  await cleanupFormAutofillStorage();
+  // add a Brazilian address (since it uses all fields) and card to avoid the FTU sequence
+  let prefilledGuids = await addSampleAddressesAndBasicCard(
+    [PTU.Addresses.TimBR], [PTU.BasicCards.JohnDoe]);
+  let expected = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+
+  info("associating the card with the billing address");
+  await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
+    billingAddressGUID: prefilledGuids.address1GUID,
+  }, true);
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: BLANK_PAGE_URL,
+  }, async browser => {
+    let {win, frame} = await setupPaymentDialog(browser, {
+      methodData: [PTU.MethodData.basicCard],
+      details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
+      options: PTU.Options.requestShippingOption,
+      merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+    });
+
+    await navigateToAddCardPage(frame, {
+      addLinkSelector: "payment-method-picker .edit-link",
+    });
+
+    await navigateToAddAddressPage(frame, {
+      addLinkSelector: ".billingAddressRow .edit-link",
+      initialPageId: "basic-card-page",
+    });
+
+    await spawnPaymentDialogTask(frame, `async () => {
+      let givenNameField = content.document.querySelector(
+        "address-form #given-name"
+      );
+      await content.fillField(givenNameField, "Timothy-edit");
+    }`);
+
+    let options = {
+      isEditing: true,
+      nextPageId: "basic-card-page",
+    };
+    await submitAddressForm(frame, null, options);
+
+    info("clicking cancel");
+    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
+
+    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
+  });
+
+  Object.assign(expected, PTU.Addresses.TimBR, {
+    "given-name": "Timothy-edit",
+    "name": "Timothy-edit João Berners-Lee",
+  });
+  let actual = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+  // timeLastModified changes and isn't relevant
+  delete actual.timeLastModified;
+  delete expected.timeLastModified;
+  SimpleTest.isDeeply(actual, expected, "Check profile didn't lose fields");
+
+  await cleanupFormAutofillStorage();
+});
--- a/browser/components/payments/test/browser/head.js
+++ b/browser/components/payments/test/browser/head.js
@@ -543,31 +543,34 @@ async function verifyCardNetwork(frame, 
        "Should have one more than the number of supported networks");
     is(networkSelect.children[0].value, "",
        "The first option should be the blank/empty option");
     is(networkSelect.value, options.expectedNetwork,
        `The network picker should have the expected value`);
   }, {options: aOptions});
 }
 
-async function submitAddressForm(frame, aAddress, aOptions = {}) {
+async function submitAddressForm(frame, aAddress, aOptions = {
+  nextPageId: "payment-summary",
+}) {
   await spawnPaymentDialogTask(frame, async (args) => {
     let {options = {}} = args;
+    let nextPageId = options.nextPageId || "payment-summary";
     let {
       PaymentTestUtils,
     } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
     let oldAddresses = await PaymentTestUtils.DialogContentUtils.getCurrentState(content);
 
     // submit the form to return to summary page
     content.document.querySelector("address-form button:last-of-type").click();
 
     let currState = await PaymentTestUtils.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "payment-summary";
-    }, "submitAddressForm: Switched back to payment-summary");
+      return state.page.id == nextPageId;
+    }, `submitAddressForm: Switched back to ${nextPageId}`);
 
     let savedCount = Object.keys(currState.savedAddresses).length;
     let tempCount = Object.keys(currState.tempAddresses).length;
     let oldSavedCount = Object.keys(oldAddresses.savedAddresses).length;
     let oldTempCount = Object.keys(oldAddresses.tempAddresses).length;
 
     if (options.isEditing) {
       is(tempCount, oldTempCount, "tempAddresses count didn't change");
@@ -612,18 +615,18 @@ async function navigateToAddCardPage(fra
     }, "Check summary page state");
 
     // click through to add/edit card page
     let addLink = content.document.querySelector(options.addLinkSelector);
     addLink.click();
 
     // wait for card page
     await PaymentTestUtils.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid;
-    }, "Check add page state");
+      return state.page.id == "basic-card-page";
+    }, "Check add/edit page state");
   }, aOptions);
 }
 
 async function fillInCardForm(frame, aCard, aOptions = {}) {
   await spawnPaymentDialogTask(frame, async (args) => {
     let {card, options = {}} = args;
 
     // fill the form
--- a/browser/components/payments/test/mochitest/test_address_form.html
+++ b/browser/components/payments/test/mochitest/test_address_form.html
@@ -771,12 +771,65 @@ add_task(async function test_field_valid
   postalCode.focus();
   sendString("12345", window);
   is(errorTextSpan.innerText, "", "DOM validation message should be removed when no error");
   postalCode.blur();
 
   form.remove();
 });
 
+add_task(async function test_hiddenMailingAddressFieldsCleared() {
+  let form = new AddressForm();
+  form.dataset.updateButtonLabel = "Update";
+  await form.promiseReady;
+  display.appendChild(form);
+  await asyncElementRendered();
+
+  let address1 = deepClone(PTU.Addresses.TimBL);
+  address1.guid = "9864798564";
+
+  await form.requestStore.setState({
+    page: {
+      id: "address-page",
+    },
+    "address-page": {
+      guid: address1.guid,
+      selectedStateKey: ["selectedShippingAddress"],
+    },
+    savedAddresses: {
+      [address1.guid]: deepClone(address1),
+    },
+  });
+  await asyncElementRendered();
+
+  info("Change the country to hide address-level1");
+  fillField(form.form.querySelector("#country"), "DE");
+
+  let expectedRecord = Object.assign({}, address1, {
+    country: "DE",
+    // address-level1 & 3 aren't used for Germany so should be blanked.
+    "address-level1": "",
+    "address-level3": "",
+  });
+  delete expectedRecord.guid;
+  // The following were not shown so shouldn't be part of the message:
+  delete expectedRecord.email;
+
+  let messagePromise = promiseContentToChromeMessage("updateAutofillRecord");
+  form.saveButton.scrollIntoView();
+  synthesizeMouseAtCenter(form.saveButton, {});
+
+  let details = await messagePromise;
+  delete details.messageID;
+  is(details.collectionName, "addresses", "Check collectionName");
+  isDeeply(details, {
+    collectionName: "addresses",
+    guid: address1.guid,
+    messageType: "updateAutofillRecord",
+    record: expectedRecord,
+  }, "Check update event details for the message to chrome");
+
+  form.remove();
+});
 </script>
 
 </body>
 </html>