Bug 1446203 - Basic Payment Request Shipping Address Add/Edit page. r=MattN
☠☠ backed out by 61784cdfb905 ☠ ☠
authorJared Wein <jwein@mozilla.com>
Tue, 10 Apr 2018 11:53:16 -0400
changeset 471998 d03421ea2005836e4ed6133b556614dbfd901745
parent 471997 9edd64fc07d3d7034c00cf1aa41b9203ecd8bb29
child 471999 11a7d6db54859ff6733733c9b244ac16c54ec657
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1446203
milestone61.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 1446203 - Basic Payment Request Shipping Address Add/Edit page. r=MattN MozReview-Commit-ID: 9f0vPciw65V
browser/installer/allowed-dupes.mn
toolkit/components/payments/content/paymentDialogFrameScript.js
toolkit/components/payments/jar.mn
toolkit/components/payments/res/containers/address-form.js
toolkit/components/payments/res/containers/address-picker.js
toolkit/components/payments/res/containers/payment-dialog.js
toolkit/components/payments/res/paymentRequest.xhtml
toolkit/components/payments/res/unprivileged-fallbacks.js
toolkit/components/payments/test/browser/browser.ini
toolkit/components/payments/test/browser/browser_address_edit.js
toolkit/components/payments/test/browser/browser_card_edit.js
toolkit/components/payments/test/mochitest/formautofill/mochitest.ini
toolkit/components/payments/test/mochitest/mochitest.ini
toolkit/components/payments/test/mochitest/test_address_form.html
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -139,12 +139,14 @@ res/table-remove-row-active.gif
 res/table-remove-row-hover.gif
 res/table-remove-row.gif
 res/multilocale.txt
 update.locale
 # Aurora branding
 browser/chrome/browser/content/branding/icon128.png
 browser/chrome/devtools/content/framework/dev-edition-promo/dev-edition-logo.png
 # Bug 1451016 - Nightly-only PaymentRequest & Form Autofill code sharing.
+browser/features/formautofill@mozilla.org/chrome/content/editAddress.xhtml
+chrome/toolkit/res/payments/formautofill/editAddress.xhtml
 browser/features/formautofill@mozilla.org/chrome/content/editCreditCard.xhtml
 chrome/toolkit/res/payments/formautofill/editCreditCard.xhtml
 browser/features/formautofill@mozilla.org/chrome/content/autofillEditForms.js
 chrome/toolkit/res/payments/formautofill/autofillEditForms.js
--- a/toolkit/components/payments/content/paymentDialogFrameScript.js
+++ b/toolkit/components/payments/content/paymentDialogFrameScript.js
@@ -60,26 +60,34 @@ let PaymentFrameScript = {
       });
     }
   },
 
   /**
    * Expose privileged utility functions to the unprivileged page.
    */
   exposeUtilityFunctions() {
+    let waivedContent = Cu.waiveXrays(content);
     let PaymentDialogUtils = {
+      DEFAULT_REGION: FormAutofillUtils.DEFAULT_REGION,
+      supportedCountries: FormAutofillUtils.supportedCountries,
+
       getAddressLabel(address) {
         return FormAutofillUtils.getAddressLabel(address);
       },
 
       isCCNumber(value) {
         return FormAutofillUtils.isCCNumber(value);
       },
+
+      getFormFormat(country) {
+        let format = FormAutofillUtils.getFormFormat(country);
+        return Cu.cloneInto(format, waivedContent);
+      },
     };
-    let waivedContent = Cu.waiveXrays(content);
     waivedContent.PaymentDialogUtils = Cu.cloneInto(PaymentDialogUtils, waivedContent, {
       cloneFunctions: true,
     });
   },
 
   sendToChrome({detail}) {
     let {messageType} = detail;
     if (messageType == "initializeRequest") {
--- a/toolkit/components/payments/jar.mn
+++ b/toolkit/components/payments/jar.mn
@@ -14,13 +14,14 @@ toolkit.jar:
     res/payments/components/                          (res/components/*.css)
     res/payments/components/                          (res/components/*.js)
     res/payments/containers/                          (res/containers/*.js)
     res/payments/containers/                          (res/containers/*.css)
     res/payments/debugging.css                        (res/debugging.css)
     res/payments/debugging.html                       (res/debugging.html)
     res/payments/debugging.js                         (res/debugging.js)
     res/payments/formautofill/autofillEditForms.js    (../../../browser/extensions/formautofill/content/autofillEditForms.js)
+    res/payments/formautofill/editAddress.xhtml       (../../../browser/extensions/formautofill/content/editAddress.xhtml)
     res/payments/formautofill/editCreditCard.xhtml    (../../../browser/extensions/formautofill/content/editCreditCard.xhtml)
     res/payments/unprivileged-fallbacks.js            (res/unprivileged-fallbacks.js)
     res/payments/mixins/                              (res/mixins/*.js)
     res/payments/PaymentsStore.js                     (res/PaymentsStore.js)
     res/payments/vendor/                              (res/vendor/*)
copy from toolkit/components/payments/res/containers/basic-card-form.js
copy to toolkit/components/payments/res/containers/address-form.js
--- a/toolkit/components/payments/res/containers/basic-card-form.js
+++ b/toolkit/components/payments/res/containers/address-form.js
@@ -1,42 +1,38 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* import-globals-from ../../../../../browser/extensions/formautofill/content/autofillEditForms.js*/
-import LabelledCheckbox from "../components/labelled-checkbox.js";
 import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js";
 import paymentRequest from "../paymentRequest.js";
-
 /* import-globals-from ../unprivileged-fallbacks.js */
 
 /**
- * <basic-card-form></basic-card-form>
+ * <address-form></address-form>
  *
  * XXX: Bug 1446164 - This form isn't localized when used via this custom element
  * as it will be much easier to share the logic once we switch to Fluent.
  */
 
-export default class BasicCardForm extends PaymentStateSubscriberMixin(HTMLElement) {
+export default class AddressForm extends PaymentStateSubscriberMixin(HTMLElement) {
   constructor() {
     super();
 
     this.genericErrorText = document.createElement("div");
 
     this.backButton = document.createElement("button");
     this.backButton.addEventListener("click", this);
 
     this.saveButton = document.createElement("button");
     this.saveButton.addEventListener("click", this);
 
-    this.persistCheckbox = new LabelledCheckbox();
-
     // The markup is shared with form autofill preferences.
-    let url = "formautofill/editCreditCard.xhtml";
+    let url = "formautofill/editAddress.xhtml";
     this.promiseReady = this._fetchMarkup(url).then(doc => {
       this.form = doc.getElementById("form");
       return this.form;
     });
   }
 
   _fetchMarkup(url) {
     return new Promise((resolve, reject) => {
@@ -51,70 +47,56 @@ export default class BasicCardForm exten
     });
   }
 
   connectedCallback() {
     this.promiseReady.then(form => {
       this.appendChild(form);
 
       let record = {};
-      let addresses = [];
-      this.formHandler = new EditCreditCard({
+      this.formHandler = new EditAddress({
         form,
-      }, record, addresses, {
-        isCCNumber: PaymentDialogUtils.isCCNumber,
-        getAddressLabel: PaymentDialogUtils.getAddressLabel,
+      }, record, {
+        DEFAULT_REGION: PaymentDialogUtils.DEFAULT_REGION,
+        getFormFormat: PaymentDialogUtils.getFormFormat,
+        supportedCountries: PaymentDialogUtils.supportedCountries,
       });
 
-      this.appendChild(this.persistCheckbox);
       this.appendChild(this.genericErrorText);
       this.appendChild(this.backButton);
       this.appendChild(this.saveButton);
       // Only call the connected super callback(s) once our markup is fully
       // connected, including the shared form fetched asynchronously.
       super.connectedCallback();
     });
   }
 
   render(state) {
     this.backButton.textContent = this.dataset.backButtonLabel;
     this.saveButton.textContent = this.dataset.saveButtonLabel;
-    this.persistCheckbox.label = this.dataset.persistCheckboxLabel;
 
     let record = {};
     let {
       page,
       savedAddresses,
-      selectedShippingAddress,
     } = state;
-    let basicCards = paymentRequest.getBasicCards(state);
 
     this.genericErrorText.textContent = page.error;
 
     let editing = !!page.guid;
-    this.form.querySelector("#cc-number").disabled = editing;
 
-    // If a card is selected we want to edit it.
+    // If an address is selected we want to edit it.
     if (editing) {
-      record = basicCards[page.guid];
+      record = savedAddresses[page.guid];
       if (!record) {
-        throw new Error("Trying to edit a non-existing card: " + page.guid);
+        throw new Error("Trying to edit a non-existing address: " + page.guid);
       }
-      // When editing an existing record, prevent changes to persistence
-      this.persistCheckbox.hidden = true;
-    } else {
-      if (selectedShippingAddress) {
-        record.billingAddressGUID = selectedShippingAddress;
-      }
-      // Adding a new record: default persistence to checked when in a not-private session
-      this.persistCheckbox.hidden = false;
-      this.persistCheckbox.checked = !state.isPrivate;
     }
 
-    this.formHandler.loadRecord(record, savedAddresses);
+    this.formHandler.loadRecord(record);
   }
 
   handleEvent(event) {
     switch (event.type) {
       case "click": {
         this.onClick(event);
         break;
       }
@@ -140,61 +122,30 @@ export default class BasicCardForm exten
       }
     }
   }
 
   saveRecord() {
     let record = this.formHandler.buildFormObject();
     let {
       page,
-      tempBasicCards,
+      selectedStateKey,
     } = this.requestStore.getState();
-    let editing = !!page.guid;
-    let tempRecord = editing && tempBasicCards[page.guid];
-
-    for (let editableFieldName of ["cc-name", "cc-exp-month", "cc-exp-year"]) {
-      record[editableFieldName] = record[editableFieldName] || "";
-    }
-
-    // Only save the card number if we're saving a new record, otherwise we'd
-    // overwrite the unmasked card number with the masked one.
-    if (!editing) {
-      record["cc-number"] = record["cc-number"] || "";
-    }
 
-    if (!tempRecord && this.persistCheckbox.checked) {
-      log.debug(`BasicCardForm: persisting creditCard record: ${page.guid || "(new)"}`);
-      paymentRequest.updateAutofillRecord("creditCards", record, page.guid, {
-        errorStateChange: {
-          page: {
-            id: "basic-card-page",
-            error: this.dataset.errorGenericSave,
-          },
+    paymentRequest.updateAutofillRecord("addresses", record, page.guid, {
+      errorStateChange: {
+        page: {
+          id: "address-page",
+          error: this.dataset.errorGenericSave,
         },
-        preserveOldProperties: true,
-        selectedStateKey: "selectedPaymentCard",
-        successStateChange: {
-          page: {
-            id: "payment-summary",
-          },
-        },
-      });
-    } else {
-      // This record will never get inserted into the store
-      // so we generate a faux-guid for a new record
-      record.guid = page.guid || "temp-" + Math.abs(Math.random() * 0xffffffff|0);
-
-      log.debug(`BasicCardForm: saving temporary record: ${record.guid}`);
-      this.requestStore.setState({
+      },
+      preserveOldProperties: true,
+      selectedStateKey,
+      successStateChange: {
         page: {
           id: "payment-summary",
         },
-        selectedPaymentCard: record.guid,
-        tempBasicCards: Object.assign({}, tempBasicCards, {
-        // Mix-in any previous values - equivalent to the store's preserveOldProperties: true,
-          [record.guid]: Object.assign({}, tempRecord, record),
-        }),
-      });
-    }
+      },
+    });
   }
 }
 
-customElements.define("basic-card-form", BasicCardForm);
+customElements.define("address-form", AddressForm);
--- a/toolkit/components/payments/res/containers/address-picker.js
+++ b/toolkit/components/payments/res/containers/address-picker.js
@@ -3,33 +3,44 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 import AddressOption from "../components/address-option.js";
 import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js";
 import RichSelect from "../components/rich-select.js";
 
 /**
  * <address-picker></address-picker>
- * Container around <rich-select> (eventually providing add/edit links) with
+ * Container around add/edit links and <rich-select> with
  * <address-option> listening to savedAddresses.
  */
 
 export default class AddressPicker extends PaymentStateSubscriberMixin(HTMLElement) {
   static get observedAttributes() {
     return ["address-fields"];
   }
 
   constructor() {
     super();
     this.dropdown = new RichSelect();
     this.dropdown.addEventListener("change", this);
+    this.addLink = document.createElement("a");
+    this.addLink.href = "javascript:void(0)";
+    this.addLink.textContent = this.dataset.addLinkLabel;
+    this.addLink.addEventListener("click", this);
+    this.editLink = document.createElement("a");
+    this.editLink.href = "javascript:void(0)";
+    this.editLink.textContent = this.dataset.editLinkLabel;
+    this.editLink.addEventListener("click", this);
   }
 
   connectedCallback() {
     this.appendChild(this.dropdown);
+    this.appendChild(this.addLink);
+    this.append(" ");
+    this.appendChild(this.editLink);
     super.connectedCallback();
   }
 
   attributeChangedCallback(name, oldValue, newValue) {
     if (oldValue !== newValue) {
       this.render(this.requestStore.getState());
     }
   }
@@ -129,23 +140,53 @@ export default class AddressPicker exten
   }
 
   handleEvent(event) {
     switch (event.type) {
       case "change": {
         this.onChange(event);
         break;
       }
+      case "click": {
+        this.onClick(event);
+      }
     }
   }
 
   onChange(event) {
     let select = event.target;
     let selectedKey = this.selectedStateKey;
     if (selectedKey) {
       this.requestStore.setState({
         [selectedKey]: select.selectedOption && select.selectedOption.guid,
       });
     }
   }
+
+  onClick({target}) {
+    let nextState = {
+      page: {
+        id: "address-page",
+        selectedStateKey: this.selectedStateKey,
+      },
+    };
+
+    switch (target) {
+      case this.addLink: {
+        nextState.page.guid = null;
+        break;
+      }
+      case this.editLink: {
+        let state = this.requestStore.getState();
+        let selectedAddressGUID = state[this.selectedStateKey];
+        nextState.page.guid = selectedAddressGUID;
+        break;
+      }
+      default: {
+        throw new Error("Unexpected onClick");
+      }
+    }
+
+    this.requestStore.setState(nextState);
+  }
 }
 
 customElements.define("address-picker", AddressPicker);
--- a/toolkit/components/payments/res/containers/payment-dialog.js
+++ b/toolkit/components/payments/res/containers/payment-dialog.js
@@ -4,16 +4,17 @@
 
 import "../vendor/custom-elements.min.js";
 
 import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js";
 import paymentRequest from "../paymentRequest.js";
 
 import "../components/currency-amount.js";
 import "./address-picker.js";
+import "./address-form.js";
 import "./basic-card-form.js";
 import "./order-details.js";
 import "./payment-method-picker.js";
 import "./shipping-option-picker.js";
 
 /* import-globals-from ../unprivileged-fallbacks.js */
 
 /**
--- a/toolkit/components/payments/res/paymentRequest.xhtml
+++ b/toolkit/components/payments/res/paymentRequest.xhtml
@@ -8,31 +8,38 @@
 
   <!ENTITY viewAllItems               "View All Items">
   <!ENTITY paymentSummaryTitle        "Your Payment">
   <!ENTITY shippingAddressLabel       "Shipping Address">
   <!ENTITY deliveryAddressLabel       "Delivery Address">
   <!ENTITY pickupAddressLabel         "Pickup Address">
   <!ENTITY shippingOptionsLabel       "Shipping Options">
   <!ENTITY paymentMethodsLabel        "Payment Method">
+  <!ENTITY address.addLink.label      "Add">
+  <!ENTITY address.editLink.label     "Edit">
   <!ENTITY basicCard.addLink.label    "Add">
   <!ENTITY basicCard.editLink.label   "Edit">
+  <!ENTITY payer.addLink.label        "Add">
+  <!ENTITY payer.editLink.label       "Edit">
   <!ENTITY payerLabel                 "Contact Information">
   <!ENTITY cancelPaymentButton.label   "Cancel">
   <!ENTITY approvePaymentButton.label  "Pay">
   <!ENTITY processingPaymentButton.label "Processing">
   <!ENTITY successPaymentButton.label    "Done">
   <!ENTITY failPaymentButton.label       "Fail">
   <!ENTITY unknownPaymentButton.label    "Unknown">
   <!ENTITY orderDetailsLabel          "Order Details">
   <!ENTITY orderTotalLabel            "Total">
   <!ENTITY basicCardPage.error.genericSave    "There was an error saving the payment card.">
   <!ENTITY basicCardPage.backButton.label     "Back">
   <!ENTITY basicCardPage.saveButton.label     "Save">
   <!ENTITY basicCardPage.persistCheckbox.label     "Save credit card to Firefox (Security code will not be saved)">
+  <!ENTITY addressPage.error.genericSave      "There was an error saving the address.">
+  <!ENTITY addressPage.backButton.label       "Back">
+  <!ENTITY addressPage.saveButton.label       "Save">
 ]>
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <title>&paymentSummaryTitle;</title>
 
   <!-- chrome: is needed for global.dtd -->
   <meta http-equiv="Content-Security-Policy" content="default-src 'self' chrome:"/>
 
@@ -70,29 +77,34 @@
         <section>
           <div id="error-text"></div>
 
           <div class="shipping-related"
                id="shipping-type-label"
                data-shipping-address-label="&shippingAddressLabel;"
                data-delivery-address-label="&deliveryAddressLabel;"
                data-pickup-address-label="&pickupAddressLabel;"><label></label></div>
-          <address-picker class="shipping-related" selected-state-key="selectedShippingAddress"></address-picker>
+          <address-picker class="shipping-related"
+                          data-add-link-label="&address.addLink.label;"
+                          data-edit-link-label="&address.editLink.label;"
+                          selected-state-key="selectedShippingAddress"></address-picker>
 
           <div class="shipping-related"><label>&shippingOptionsLabel;</label></div>
           <shipping-option-picker class="shipping-related"></shipping-option-picker>
 
           <div><label>&paymentMethodsLabel;</label></div>
           <payment-method-picker selected-state-key="selectedPaymentCard"
                                  data-add-link-label="&basicCard.addLink.label;"
                                  data-edit-link-label="&basicCard.editLink.label;">
           </payment-method-picker>
 
           <div class="payer-related"><label>&payerLabel;</label></div>
           <address-picker class="payer-related"
+                          data-add-link-label="&payer.addLink.label;"
+                          data-edit-link-label="&payer.editLink.label;"
                           selected-state-key="selectedPayerAddress"></address-picker>
           <div id="error-text"></div>
         </section>
 
         <footer id="controls-container">
           <button id="cancel">&cancelPaymentButton.label;</button>
           <button id="pay"
                   data-initial-label="&approvePaymentButton.label;"
@@ -109,16 +121,23 @@
 
       <basic-card-form id="basic-card-page"
                        class="page"
                        data-error-generic-save="&basicCardPage.error.genericSave;"
                        data-back-button-label="&basicCardPage.backButton.label;"
                        data-save-button-label="&basicCardPage.saveButton.label;"
                        data-persist-checkbox-label="&basicCardPage.persistCheckbox.label;"
                        hidden="hidden"></basic-card-form>
+
+      <address-form id="address-page"
+                    class="page"
+                    data-error-generic-save="&addressPage.error.genericSave;"
+                    data-back-button-label="&addressPage.backButton.label;"
+                    data-save-button-label="&addressPage.saveButton.label;"
+                    hidden="hidden"></address-form>
     </div>
 
     <div id="disabled-overlay" hidden="hidden">
       <!-- overlay to prevent changes while waiting for a response from the merchant -->
     </div>
   </template>
 
   <template id="order-details-template">
--- a/toolkit/components/payments/res/unprivileged-fallbacks.js
+++ b/toolkit/components/payments/res/unprivileged-fallbacks.js
@@ -23,9 +23,25 @@ var log = {
 
 var PaymentDialogUtils = {
   getAddressLabel(address) {
     return `${address.name} (${address.guid})`;
   },
   isCCNumber(str) {
     return str.length > 0;
   },
+  DEFAULT_REGION: "US",
+  supportedCountries: ["US", "CA"],
+  getFormFormat(country) {
+    return {
+      "addressLevel1Label": country == "US" ? "state" : "province",
+      "postalCodeLabel": country == "US" ? "zip" : "postalCode",
+      "fieldsOrder": [
+        {fieldId: "name", newLine: true},
+        {fieldId: "organization", newLine: true},
+        {fieldId: "street-address", newLine: true},
+        {fieldId: "address-level2"},
+        {fieldId: "address-level1"},
+        {fieldId: "postal-code"},
+      ],
+    };
+  },
 };
--- a/toolkit/components/payments/test/browser/browser.ini
+++ b/toolkit/components/payments/test/browser/browser.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 head = head.js
 prefs =
   dom.payments.request.enabled=true
 skip-if = !e10s # Bug 1365964 - Payment Request isn't implemented for non-e10s
 support-files =
   blank_page.html
 
+[browser_address_edit.js]
 [browser_card_edit.js]
 [browser_change_shipping.js]
 [browser_host_name.js]
 [browser_profile_storage.js]
 [browser_request_serialization.js]
 [browser_request_shipping.js]
 [browser_request_summary.js]
 uses-unsafe-cpows = true
copy from toolkit/components/payments/test/browser/browser_card_edit.js
copy to toolkit/components/payments/test/browser/browser_address_edit.js
--- a/toolkit/components/payments/test/browser/browser_card_edit.js
+++ b/toolkit/components/payments/test/browser/browser_address_edit.js
@@ -1,221 +1,157 @@
 "use strict";
 
 add_task(async function test_add_link() {
-  const args = {
-    methodData: [PTU.MethodData.basicCard],
-    details: PTU.Details.total60USD,
-  };
-  await spawnInDialogForMerchantTask(PTU.ContentTasks.createRequest, async function check() {
-    let {
-      PaymentTestUtils: PTU,
-    } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-    let addLink = content.document.querySelector("payment-method-picker a");
-    is(addLink.textContent, "Add", "Add link text");
-
-    addLink.click();
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: BLANK_PAGE_URL,
+  }, async browser => {
+    let {win, frame} =
+      await setupPaymentDialog(browser, {
+        methodData: [PTU.MethodData.basicCard],
+        details: PTU.Details.twoShippingOptions,
+        options: PTU.Options.requestShippingOption,
+        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+      }
+    );
 
-    let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
-    },
-                                                          "Check add page state");
+    let shippingAddressChangePromise = ContentTask.spawn(browser, {
+      eventName: "shippingaddresschange",
+    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
 
-    ok(!state.isPrivate,
-       "isPrivate flag is not set when paymentrequest is shown from a non-private session");
-    let persistInput = content.document.querySelector("basic-card-form labelled-checkbox");
-    ok(Cu.waiveXrays(persistInput).checked, "persist checkbox should be checked by default");
-
-    let year = (new Date()).getFullYear();
-    let card = {
-      "cc-number": "4111111111111111",
-      "cc-name": "J. Smith",
-      "cc-exp-month": 11,
-      "cc-exp-year": year,
+    const EXPECTED_ADDRESS = {
+      "given-name": "Jared",
+      "family-name": "Wein",
+      "organization": "Mozilla",
+      "street-address": "404 Internet Lane",
+      "address-level2": "Firefoxity City",
+      "address-level1": "CA",
+      "postal-code": "31337",
+      "country": "US",
+      "tel": "+15555551212",
+      "email": "test@example.com",
     };
 
-    info("filling fields");
-    for (let [key, val] of Object.entries(card)) {
-      let field = content.document.getElementById(key);
-      field.value = val;
-      ok(!field.disabled, `Field #${key} shouldn't be disabled`);
-    }
+    await spawnPaymentDialogTask(frame, async (address) => {
+      let {
+        PaymentTestUtils: PTU,
+      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
+
+      let addLink = content.document.querySelector("address-picker a");
+      is(addLink.textContent, "Add", "Add link text");
+
+      addLink.click();
 
-    content.document.querySelector("basic-card-form button:last-of-type").click();
+      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+        return state.page.id == "address-page" && !state.page.guid;
+      }, "Check add page state");
 
-    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return Object.keys(state.savedBasicCards).length == 1;
-    },
-                                                      "Check card was added");
+      info("filling fields");
+      for (let [key, val] of Object.entries(address)) {
+        let field = content.document.getElementById(key);
+        if (!field) {
+          ok(false, `${key} field not found`);
+        }
+        field.value = val;
+        ok(!field.disabled, `Field #${key} shouldn't be disabled`);
+      }
 
-    let cardGUIDs = Object.keys(state.savedBasicCards);
-    is(cardGUIDs.length, 1, "Check there is one card");
-    let savedCard = state.savedBasicCards[cardGUIDs[0]];
-    card["cc-number"] = "************1111"; // Card should be masked
-    for (let [key, val] of Object.entries(card)) {
-      is(savedCard[key], val, "Check " + key);
-    }
+      content.document.querySelector("address-form button:last-of-type").click();
+      state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+        return Object.keys(state.savedAddresses).length == 1;
+      }, "Check address was added");
+
+      let addressGUIDs = Object.keys(state.savedAddresses);
+      is(addressGUIDs.length, 1, "Check there is one address");
+      let savedAddress = state.savedAddresses[addressGUIDs[0]];
+      for (let [key, val] of Object.entries(address)) {
+        is(savedAddress[key], val, "Check " + key);
+      }
 
-    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "payment-summary";
-    },
-                                                      "Switched back to payment-summary");
-  }, args);
+      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");
+    await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
+
+    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
+  });
 });
 
 add_task(async function test_edit_link() {
-  const args = {
-    methodData: [PTU.MethodData.basicCard],
-    details: PTU.Details.total60USD,
-  };
-  await spawnInDialogForMerchantTask(PTU.ContentTasks.createRequest, async function check() {
-    let {
-      PaymentTestUtils: PTU,
-    } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-    let editLink = content.document.querySelector("payment-method-picker a:nth-of-type(2)");
-    is(editLink.textContent, "Edit", "Edit link text");
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: BLANK_PAGE_URL,
+  }, async browser => {
+    let {win, frame} =
+      await setupPaymentDialog(browser, {
+        methodData: [PTU.MethodData.basicCard],
+        details: PTU.Details.twoShippingOptions,
+        options: PTU.Options.requestShippingOption,
+        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+      }
+    );
 
-    editLink.click();
-
-    let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !!state.page.guid;
-    },
-                                                          "Check edit page state");
+    let shippingAddressChangePromise = ContentTask.spawn(browser, {
+      eventName: "shippingaddresschange",
+    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
 
-    let nextYear = (new Date()).getFullYear() + 1;
-    let card = {
-      // cc-number cannot be modified
-      "cc-name": "A. Nonymous",
-      "cc-exp-month": 3,
-      "cc-exp-year": nextYear,
+    const EXPECTED_ADDRESS = {
+      "given-name": "Jaws",
+      "family-name": "swaJ",
+      "organization": "aliizoM",
     };
 
-    info("overwriting field values");
-    for (let [key, val] of Object.entries(card)) {
-      let field = content.document.getElementById(key);
-      field.value = val;
-      ok(!field.disabled, `Field #${key} shouldn't be disabled`);
-    }
-    ok(content.document.getElementById("cc-number").disabled, "cc-number field should be disabled");
-
-    content.document.querySelector("basic-card-form button:last-of-type").click();
-
-    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return Object.keys(state.savedBasicCards).length == 1;
-    },
-                                                      "Check card was added");
+    await spawnPaymentDialogTask(frame, async (address) => {
+      let {
+        PaymentTestUtils: PTU,
+      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
-    let cardGUIDs = Object.keys(state.savedBasicCards);
-    is(cardGUIDs.length, 1, "Check there is still one card");
-    let savedCard = state.savedBasicCards[cardGUIDs[0]];
-    is(savedCard["cc-number"], "************1111", "Card number should be masked and unmodified.");
-    for (let [key, val] of Object.entries(card)) {
-      is(savedCard[key], val, "Check updated " + key);
-    }
+      let editLink = content.document.querySelector("address-picker a:nth-of-type(2)");
+      is(editLink.textContent, "Edit", "Edit link text");
 
-    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "payment-summary";
-    },
-                                                      "Switched back to payment-summary");
-  }, args);
-});
+      editLink.click();
 
-add_task(async function test_private_persist_defaults() {
-  const args = {
-    methodData: [PTU.MethodData.basicCard],
-    details: PTU.Details.total60USD,
-  };
-  await spawnInDialogForMerchantTask(PTU.ContentTasks.createRequest, async function check() {
-    let {
-      PaymentTestUtils: PTU,
-    } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-    let addLink = content.document.querySelector("payment-method-picker a");
-    is(addLink.textContent, "Add", "Add link text");
-
-    addLink.click();
+      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+        return state.page.id == "address-page" && !!state.page.guid;
+      }, "Check edit page state");
 
-    let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
-    },
-                                                          "Check add page state");
+      info("overwriting field values");
+      for (let [key, val] of Object.entries(address)) {
+        let field = content.document.getElementById(key);
+        field.value = val;
+        ok(!field.disabled, `Field #${key} shouldn't be disabled`);
+      }
 
-    ok(!state.isPrivate,
-       "isPrivate flag is not set when paymentrequest is shown from a non-private session");
-    let persistInput = content.document.querySelector("basic-card-form labelled-checkbox");
-    ok(Cu.waiveXrays(persistInput).checked,
-       "checkbox is checked by default from a non-private session");
-  }, args);
-
-  await spawnInDialogForPrivateMerchantTask(PTU.ContentTasks.createRequest, async function check() {
-    let {
-      PaymentTestUtils: PTU,
-    } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-    let addLink = content.document.querySelector("payment-method-picker a");
-    is(addLink.textContent, "Add", "Add link text");
+      content.document.querySelector("address-form button:last-of-type").click();
 
-    addLink.click();
-
-    let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
-    },
-                                                          "Check add page state");
-
-    ok(state.isPrivate,
-       "isPrivate flag is set when paymentrequest is shown from a private session");
-    let persistInput = content.document.querySelector("labelled-checkbox");
-    ok(!Cu.waiveXrays(persistInput).checked,
-       "checkbox is not checked by default from a private session");
-  }, args);
-});
+      state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+        return Object.keys(state.savedAddresses).length == 1;
+      }, "Check address was edited");
 
-add_task(async function test_private_card_adding() {
-  const args = {
-    methodData: [PTU.MethodData.basicCard],
-    details: PTU.Details.total60USD,
-  };
-  await spawnInDialogForPrivateMerchantTask(PTU.ContentTasks.createRequest, async function check() {
-    let {
-      PaymentTestUtils: PTU,
-    } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-    let addLink = content.document.querySelector("payment-method-picker a");
-    is(addLink.textContent, "Add", "Add link text");
-
-    addLink.click();
+      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);
+      }
 
-    let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state.page.guid;
-    },
-                                                          "Check add page state");
-
-    let savedCardCount = Object.keys(state.savedBasicCards).length;
-    let tempCardCount = Object.keys(state.tempBasicCards).length;
+      state = await PTU.DialogContentUtils.waitForState(content, (state) => {
+        return state.page.id == "payment-summary";
+      }, "Switched back to payment-summary");
+    }, EXPECTED_ADDRESS);
 
-    let year = (new Date()).getFullYear();
-    let card = {
-      "cc-number": "4111111111111111",
-      "cc-name": "J. Smith",
-      "cc-exp-month": 11,
-      "cc-exp-year": year,
-    };
+    await shippingAddressChangePromise;
+    info("got shippingaddresschange event");
 
-    info("filling fields");
-    for (let [key, val] of Object.entries(card)) {
-      let field = content.document.getElementById(key);
-      field.value = val;
-      ok(!field.disabled, `Field #${key} shouldn't be disabled`);
-    }
-
-    content.document.querySelector("basic-card-form button:last-of-type").click();
+    info("clicking cancel");
+    await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
 
-    state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-      return Object.keys(state.tempBasicCards).length > tempCardCount;
-    },
-                                                      "Check card was added to temp collection");
-
-    is(savedCardCount, Object.keys(state.savedBasicCards).length, "No card was saved in state");
-    is(Object.keys(state.tempBasicCards).length, 1, "Card was added temporarily");
-  }, args);
+    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
+  });
+  await cleanupFormAutofillStorage();
 });
--- a/toolkit/components/payments/test/browser/browser_card_edit.js
+++ b/toolkit/components/payments/test/browser/browser_card_edit.js
@@ -12,18 +12,17 @@ add_task(async function test_add_link() 
 
     let addLink = content.document.querySelector("payment-method-picker a");
     is(addLink.textContent, "Add", "Add link text");
 
     addLink.click();
 
     let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return state.page.id == "basic-card-page" && !state.page.guid;
-    },
-                                                          "Check add page state");
+    }, "Check add page state");
 
     ok(!state.isPrivate,
        "isPrivate flag is not set when paymentrequest is shown from a non-private session");
     let persistInput = content.document.querySelector("basic-card-form labelled-checkbox");
     ok(Cu.waiveXrays(persistInput).checked, "persist checkbox should be checked by default");
 
     let year = (new Date()).getFullYear();
     let card = {
@@ -39,31 +38,29 @@ add_task(async function test_add_link() 
       field.value = val;
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
 
     content.document.querySelector("basic-card-form button:last-of-type").click();
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return Object.keys(state.savedBasicCards).length == 1;
-    },
-                                                      "Check card was added");
+    }, "Check card was added");
 
     let cardGUIDs = Object.keys(state.savedBasicCards);
     is(cardGUIDs.length, 1, "Check there is one card");
     let savedCard = state.savedBasicCards[cardGUIDs[0]];
     card["cc-number"] = "************1111"; // Card should be masked
     for (let [key, val] of Object.entries(card)) {
       is(savedCard[key], val, "Check " + key);
     }
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return state.page.id == "payment-summary";
-    },
-                                                      "Switched back to payment-summary");
+    }, "Switched back to payment-summary");
   }, args);
 });
 
 add_task(async function test_edit_link() {
   const args = {
     methodData: [PTU.MethodData.basicCard],
     details: PTU.Details.total60USD,
   };
@@ -74,18 +71,17 @@ add_task(async function test_edit_link()
 
     let editLink = content.document.querySelector("payment-method-picker a:nth-of-type(2)");
     is(editLink.textContent, "Edit", "Edit link text");
 
     editLink.click();
 
     let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return state.page.id == "basic-card-page" && !!state.page.guid;
-    },
-                                                          "Check edit page state");
+    }, "Check edit page state");
 
     let nextYear = (new Date()).getFullYear() + 1;
     let card = {
       // cc-number cannot be modified
       "cc-name": "A. Nonymous",
       "cc-exp-month": 3,
       "cc-exp-year": nextYear,
     };
@@ -97,31 +93,29 @@ add_task(async function test_edit_link()
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
     ok(content.document.getElementById("cc-number").disabled, "cc-number field should be disabled");
 
     content.document.querySelector("basic-card-form button:last-of-type").click();
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return Object.keys(state.savedBasicCards).length == 1;
-    },
-                                                      "Check card was added");
+    }, "Check card was added");
 
     let cardGUIDs = Object.keys(state.savedBasicCards);
     is(cardGUIDs.length, 1, "Check there is still one card");
     let savedCard = state.savedBasicCards[cardGUIDs[0]];
     is(savedCard["cc-number"], "************1111", "Card number should be masked and unmodified.");
     for (let [key, val] of Object.entries(card)) {
       is(savedCard[key], val, "Check updated " + key);
     }
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return state.page.id == "payment-summary";
-    },
-                                                      "Switched back to payment-summary");
+    }, "Switched back to payment-summary");
   }, args);
 });
 
 add_task(async function test_private_persist_defaults() {
   const args = {
     methodData: [PTU.MethodData.basicCard],
     details: PTU.Details.total60USD,
   };
--- a/toolkit/components/payments/test/mochitest/formautofill/mochitest.ini
+++ b/toolkit/components/payments/test/mochitest/formautofill/mochitest.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 # This manifest mostly exists so that the support-files below can be referenced
 # from a relative path of formautofill/* from the tests in the above directory
 # to resemble the layout in the shipped JAR file.
 support-files =
    ../../../../../../browser/extensions/formautofill/content/editCreditCard.xhtml
+   ../../../../../../browser/extensions/formautofill/content/editAddress.xhtml
 
 [test_editCreditCard.html]
--- a/toolkit/components/payments/test/mochitest/mochitest.ini
+++ b/toolkit/components/payments/test/mochitest/mochitest.ini
@@ -1,19 +1,21 @@
 [DEFAULT]
 prefs =
    dom.webcomponents.customelements.enabled=false
 support-files =
+   !/browser/extensions/formautofill/content/editAddress.xhtml
    !/browser/extensions/formautofill/content/editCreditCard.xhtml
    ../../../../../browser/extensions/formautofill/content/autofillEditForms.js
    ../../../../../testing/modules/sinon-2.3.2.js
    ../../res/**
    payments_common.js
 skip-if = !e10s
 
+[test_address_form.html]
 [test_address_picker.html]
 [test_basic_card_form.html]
 [test_currency_amount.html]
 [test_labelled_checkbox.html]
 [test_order_details.html]
 [test_payer_address_picker.html]
 [test_payment_dialog.html]
 [test_payment_details_item.html]
copy from toolkit/components/payments/test/mochitest/test_basic_card_form.html
copy to toolkit/components/payments/test/mochitest/test_address_form.html
--- a/toolkit/components/payments/test/mochitest/test_basic_card_form.html
+++ b/toolkit/components/payments/test/mochitest/test_address_form.html
@@ -1,16 +1,16 @@
 <!DOCTYPE HTML>
 <html>
 <!--
-Test the basic-card-form element
+Test the address-form element
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test the basic-card-form element</title>
+  <title>Test the address-form element</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/AddTask.js"></script>
   <script src="sinon-2.3.2.js"></script>
   <script src="payments_common.js"></script>
   <script src="../../res/vendor/custom-elements.min.js"></script>
   <script src="../../res/unprivileged-fallbacks.js"></script>
   <script src="autofillEditForms.js"></script>
@@ -22,276 +22,210 @@ Test the basic-card-form element
   <p id="display">
   </p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 </pre>
 <script type="module">
-/** Test the basic-card-form element **/
+/** Test the address-form element **/
 
 /* global sinon */
 /* import-globals-from payments_common.js */
 
-import BasicCardForm from "../../res/containers/basic-card-form.js";
+import AddressForm from "../../res/containers/address-form.js";
 
 let display = document.getElementById("display");
 
-function checkCCForm(customEl, expectedCard) {
-  const CC_PROPERTY_NAMES = [
-    "billingAddressGUID",
-    "cc-number",
-    "cc-name",
-    "cc-exp-month",
-    "cc-exp-year",
+function checkAddressForm(customEl, expectedAddress) {
+  const ADDRESS_PROPERTY_NAMES = [
+    "given-name",
+    "family-name",
+    "organization",
+    "street-address",
+    "address-level2",
+    "address-level1",
+    "postal-code",
+    "country",
+    "email",
+    "tel",
   ];
-  for (let propName of CC_PROPERTY_NAMES) {
-    let expectedVal = expectedCard[propName] || "";
+  for (let propName of ADDRESS_PROPERTY_NAMES) {
+    let expectedVal = expectedAddress[propName] || "";
     is(document.getElementById(propName).value,
        expectedVal.toString(),
        `Check ${propName}`);
   }
 }
 
 add_task(async function test_initialState() {
-  let form = new BasicCardForm();
+  let form = new AddressForm();
   let {page} = form.requestStore.getState();
   is(page.id, "payment-summary", "Check initial page");
   await form.promiseReady;
   display.appendChild(form);
   await asyncElementRendered();
   is(page.id, "payment-summary", "Check initial page after appending");
   form.remove();
 });
 
 add_task(async function test_backButton() {
-  let form = new BasicCardForm();
+  let form = new AddressForm();
   form.dataset.backButtonLabel = "Back";
   await form.requestStore.setState({
     page: {
       id: "test-page",
     },
   });
   await form.promiseReady;
   display.appendChild(form);
   await asyncElementRendered();
 
   let stateChangePromise = promiseStateChange(form.requestStore);
   is(form.backButton.textContent, "Back", "Check label");
+  form.backButton.scrollIntoView();
   synthesizeMouseAtCenter(form.backButton, {});
 
   let {page} = await stateChangePromise;
   is(page.id, "payment-summary", "Check initial page after appending");
 
   form.remove();
 });
 
 add_task(async function test_saveButton() {
-  let form = new BasicCardForm();
+  let form = new AddressForm();
   form.dataset.saveButtonLabel = "Save";
   form.dataset.errorGenericSave = "Generic error";
   await form.promiseReady;
   display.appendChild(form);
   await asyncElementRendered();
 
-  form.form.querySelector("#cc-number").focus();
-  sendString("4111111111111111");
-  form.form.querySelector("#cc-name").focus();
-  sendString("J. Smith");
-  form.form.querySelector("#cc-exp-month").focus();
-  sendString("11");
-  form.form.querySelector("#cc-exp-year").focus();
-  let year = (new Date()).getFullYear().toString();
-  sendString(year);
+  form.form.querySelector("#given-name").focus();
+  sendString("Jaws");
+  form.form.querySelector("#family-name").focus();
+  sendString("Swaj");
+  form.form.querySelector("#organization").focus();
+  sendString("Allizom");
+  form.form.querySelector("#street-address").focus();
+  sendString("404 Internet Super Highway");
+  form.form.querySelector("#address-level2").focus();
+  sendString("Firefoxity City");
+  form.form.querySelector("#address-level1").focus();
+  sendString("CA");
+  form.form.querySelector("#postal-code").focus();
+  sendString("00001");
+  form.form.querySelector("#country option[value='US']").selected = true;
+  form.form.querySelector("#email").focus();
+  sendString("test@example.com");
+  form.form.querySelector("#tel").focus();
+  sendString("+15555551212");
 
   let messagePromise = promiseContentToChromeMessage("updateAutofillRecord");
   is(form.saveButton.textContent, "Save", "Check label");
+  form.saveButton.scrollIntoView();
   synthesizeMouseAtCenter(form.saveButton, {});
 
   let details = await messagePromise;
-  is(details.collectionName, "creditCards", "Check collectionName");
+  is(details.collectionName, "addresses", "Check collectionName");
   isDeeply(details, {
-    collectionName: "creditCards",
+    collectionName: "addresses",
     errorStateChange: {
       page: {
-        id: "basic-card-page",
+        id: "address-page",
         error: "Generic error",
       },
     },
     guid: undefined,
     messageType: "updateAutofillRecord",
     preserveOldProperties: true,
     record: {
-      "cc-exp-month": "11",
-      "cc-exp-year": year,
-      "cc-name": "J. Smith",
-      "cc-number": "4111111111111111",
+      "given-name": "Jaws",
+      "family-name": "Swaj",
+      "organization": "Allizom",
+      "street-address": "404 Internet Super Highway",
+      "address-level2": "Firefoxity City",
+      "address-level1": "CA",
+      "postal-code": "00001",
+      "country": "US",
+      "email": "test@example.com",
+      "tel": "+15555551212",
     },
-    selectedStateKey: "selectedPaymentCard",
+    selectedStateKey: undefined,
     successStateChange: {
       page: {
         id: "payment-summary",
       },
     },
   }, "Check event details for the message to chrome");
   form.remove();
 });
 
 add_task(async function test_genericError() {
-  let form = new BasicCardForm();
+  let form = new AddressForm();
   await form.requestStore.setState({
     page: {
       id: "test-page",
       error: "Generic Error",
     },
   });
   await form.promiseReady;
   display.appendChild(form);
   await asyncElementRendered();
 
   ok(!isHidden(form.genericErrorText), "Error message should be visible");
   is(form.genericErrorText.textContent, "Generic Error", "Check error message");
   form.remove();
 });
 
-add_task(async function test_add_selectedShippingAddress() {
-  let form = new BasicCardForm();
+add_task(async function test_edit() {
+  let form = new AddressForm();
   await form.promiseReady;
   display.appendChild(form);
   await asyncElementRendered();
 
-  info("have an existing card in storage");
-  let card1 = deepClone(PTU.BasicCards.JohnDoe);
-  card1.guid = "9864798564";
-  card1["cc-exp-year"] = 2011;
-
   let address1 = deepClone(PTU.Addresses.TimBL);
-  address1.guid = "TimBLGUID";
+  address1.guid = "9864798564";
 
   await form.requestStore.setState({
     page: {
-      id: "basic-card-page",
-    },
-    savedAddresses: {
-      [address1.guid]: deepClone(address1),
-    },
-    savedBasicCards: {
-      [card1.guid]: deepClone(card1),
-    },
-    selectedShippingAddress: address1.guid,
-  });
-  await asyncElementRendered();
-  checkCCForm(form, {
-    billingAddressGUID: address1.guid,
-  });
-
-  form.remove();
-  await form.requestStore.reset();
-});
-
-add_task(async function test_add_noSelectedShippingAddress() {
-  let form = new BasicCardForm();
-  await form.promiseReady;
-  display.appendChild(form);
-  await asyncElementRendered();
-
-  info("have an existing card in storage but unused");
-  let card1 = deepClone(PTU.BasicCards.JohnDoe);
-  card1.guid = "9864798564";
-  card1["cc-exp-year"] = 2011;
-
-  let address1 = deepClone(PTU.Addresses.TimBL);
-  address1.guid = "TimBLGUID";
-
-  await form.requestStore.setState({
-    page: {
-      id: "basic-card-page",
+      id: "address-page",
+      guid: address1.guid,
     },
     savedAddresses: {
       [address1.guid]: deepClone(address1),
     },
-    savedBasicCards: {
-      [card1.guid]: deepClone(card1),
-    },
-    selectedShippingAddress: null,
-  });
-  await asyncElementRendered();
-  checkCCForm(form, {});
-
-  info("now test with a missing selectedShippingAddress");
-  await form.requestStore.setState({
-    selectedShippingAddress: "some-missing-guid",
   });
   await asyncElementRendered();
-  checkCCForm(form, {});
-
-  form.remove();
-  await form.requestStore.reset();
-});
-
-add_task(async function test_edit() {
-  let form = new BasicCardForm();
-  await form.promiseReady;
-  display.appendChild(form);
-  await asyncElementRendered();
-
-  info("test year before current");
-  let card1 = deepClone(PTU.BasicCards.JohnDoe);
-  card1.guid = "9864798564";
-  card1["cc-exp-year"] = 2011;
-
-  await form.requestStore.setState({
-    page: {
-      id: "basic-card-page",
-      guid: card1.guid,
-    },
-    savedBasicCards: {
-      [card1.guid]: deepClone(card1),
-    },
-  });
-  await asyncElementRendered();
-  checkCCForm(form, card1);
-
-  info("test future year");
-  card1["cc-exp-year"] = 2100;
-
-  await form.requestStore.setState({
-    savedBasicCards: {
-      [card1.guid]: deepClone(card1),
-    },
-  });
-  await asyncElementRendered();
-  checkCCForm(form, card1);
+  checkAddressForm(form, address1);
 
   info("test change to minimal record");
-  let minimalCard = {
-    // no expiration date or name
-    "cc-number": "1234567690123",
+  let minimalAddress = {
+    "given-name": address1["given-name"],
     guid: "9gnjdhen46",
   };
   await form.requestStore.setState({
     page: {
-      id: "basic-card-page",
-      guid: minimalCard.guid,
+      id: "address-page",
+      guid: minimalAddress.guid,
     },
-    savedBasicCards: {
-      [minimalCard.guid]: deepClone(minimalCard),
+    savedAddresses: {
+      [minimalAddress.guid]: deepClone(minimalAddress),
     },
   });
   await asyncElementRendered();
-  checkCCForm(form, minimalCard);
+  checkAddressForm(form, minimalAddress);
 
-  info("change to no selected card");
+  info("change to no selected address");
   await form.requestStore.setState({
     page: {
-      id: "basic-card-page",
+      id: "address-page",
     },
   });
   await asyncElementRendered();
-  checkCCForm(form, {});
+  checkAddressForm(form, {});
 
   form.remove();
 });
 </script>
 
 </body>
 </html>