Bug 1475760 - Take address-fields into account for payer/contact picker dropdown labels. r=MattN
authorprathiksha <prathikshaprasadsuman@gmail.com>
Mon, 20 Aug 2018 13:23:43 -0700
changeset 432445 db83318361c5
parent 432444 9044d545791f
child 432446 8229a612b15e
push id106743
push usermozilla@noorenberghe.ca
push dateMon, 20 Aug 2018 20:32:10 +0000
treeherdermozilla-inbound@db83318361c5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1475760
milestone63.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 1475760 - Take address-fields into account for payer/contact picker dropdown labels. r=MattN Differential Revision: https://phabricator.services.mozilla.com/D2831
browser/components/payments/content/paymentDialogFrameScript.js
browser/components/payments/res/components/address-option.js
browser/components/payments/res/containers/address-picker.js
browser/components/payments/res/unprivileged-fallbacks.js
browser/components/payments/test/browser/browser_address_edit.js
browser/extensions/formautofill/FormAutofillUtils.jsm
--- a/browser/components/payments/content/paymentDialogFrameScript.js
+++ b/browser/components/payments/content/paymentDialogFrameScript.js
@@ -71,18 +71,18 @@ let PaymentFrameScript = {
    * Expose privileged utility functions to the unprivileged page.
    */
   exposeUtilityFunctions() {
     let waivedContent = Cu.waiveXrays(content);
     let PaymentDialogUtils = {
       DEFAULT_REGION: FormAutofill.DEFAULT_REGION,
       supportedCountries: FormAutofill.supportedCountries,
 
-      getAddressLabel(address) {
-        return FormAutofillUtils.getAddressLabel(address);
+      getAddressLabel(address, addressFields = null) {
+        return FormAutofillUtils.getAddressLabel(address, addressFields);
       },
 
       isCCNumber(value) {
         return FormAutofillUtils.isCCNumber(value);
       },
 
       getFormFormat(country) {
         let format = FormAutofillUtils.getFormFormat(country);
--- a/browser/components/payments/res/components/address-option.js
+++ b/browser/components/payments/res/components/address-option.js
@@ -52,18 +52,18 @@ export default class AddressOption exten
 
   connectedCallback() {
     for (let name of ["name", "street-address", "email", "tel"]) {
       this.appendChild(this[`_${name}`]);
     }
     super.connectedCallback();
   }
 
-  static formatSingleLineLabel(address) {
-    return PaymentDialogUtils.getAddressLabel(address);
+  static formatSingleLineLabel(address, addressFields) {
+    return PaymentDialogUtils.getAddressLabel(address, addressFields);
   }
 
   render() {
     // Fall back to empty strings to prevent 'null' from appearing.
     this._name.textContent = this.name || "";
     this["_street-address"].textContent =
       `${this.streetAddress || ""} ${this.addressLevel2 || ""} ` +
       `${this.addressLevel1 || ""} ${this.postalCode || ""} ${this.country || ""}`;
--- a/browser/components/payments/res/containers/address-picker.js
+++ b/browser/components/payments/res/containers/address-picker.js
@@ -95,17 +95,20 @@ export default class AddressPicker exten
         let val = address[key];
         if (val) {
           optionEl.setAttribute(key, val);
         } else {
           optionEl.removeAttribute(key);
         }
       }
 
-      optionEl.textContent = AddressOption.formatSingleLineLabel(address);
+      // fieldNames getter is not used here because it returns a default array with
+      // attributes even when "address-fields" observed attribute is null.
+      let addressFields = this.getAttribute("address-fields");
+      optionEl.textContent = AddressOption.formatSingleLineLabel(address, addressFields);
       desiredOptions.push(optionEl);
     }
 
     this.dropdown.popupBox.textContent = "";
     for (let option of desiredOptions) {
       this.dropdown.popupBox.appendChild(option);
     }
 
--- a/browser/components/payments/res/unprivileged-fallbacks.js
+++ b/browser/components/payments/res/unprivileged-fallbacks.js
@@ -17,17 +17,22 @@
 var log = {
   error: console.error.bind(console, "paymentRequest.xhtml:"),
   warn: console.warn.bind(console, "paymentRequest.xhtml:"),
   info: console.info.bind(console, "paymentRequest.xhtml:"),
   debug: console.debug.bind(console, "paymentRequest.xhtml:"),
 };
 
 var PaymentDialogUtils = {
-  getAddressLabel(address) {
+  getAddressLabel(address, addressFields = null) {
+    if (addressFields) {
+      let requestedFields = addressFields.trim().split(/\s+/);
+      return requestedFields.filter(f => f && address[f]).map(f => address[f]).join(", ") +
+        ` (${address.guid})`;
+    }
     return `${address.name} (${address.guid})`;
   },
   isCCNumber(str) {
     return !!str.replace(/[-\s]/g, "").match(/^\d{9,}$/);
   },
   DEFAULT_REGION: "US",
   supportedCountries: ["US", "CA"],
   getFormFormat(country) {
--- a/browser/components/payments/test/browser/browser_address_edit.js
+++ b/browser/components/payments/test/browser/browser_address_edit.js
@@ -370,16 +370,99 @@ add_task(async function test_edit_payer_
 
     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];
+      ok(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");
+      ok(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() {
   let prefilledGuids = await setup();
 
   is((await formAutofillStorage.addresses.getAll()).length, 1,
      "Setup results in 1 stored address at start of test");
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -241,51 +241,56 @@ this.FormAutofillUtils = {
 
   getAddressSeparator() {
     // The separator should be based on the L10N address format, and using a
     // white space is a temporary solution.
     return " ";
   },
 
   /**
-   * Get address display label. It should display up to two pieces of
-   * information, separated by a comma.
+   * Get address display label. It should display information separated
+   * by a comma.
    *
    * @param  {object} address
+   * @param  {string?} addressFields Override the fields which can be displayed, but not the order.
    * @returns {string}
    */
-  getAddressLabel(address) {
+  getAddressLabel(address, addressFields = null) {
     // TODO: Implement a smarter way for deciding what to display
     //       as option text. Possibly improve the algorithm in
     //       ProfileAutoCompleteResult.jsm and reuse it here.
-    const fieldOrder = [
+    let fieldOrder = [
       "name",
       "-moz-street-address-one-line",  // Street address
       "address-level2",  // City/Town
       "organization",    // Company or organization name
       "address-level1",  // Province/State (Standardized code if possible)
       "country-name",    // Country name
       "postal-code",     // Postal code
       "tel",             // Phone number
       "email",           // Email address
     ];
 
     address = {...address};
     let parts = [];
+    if (addressFields) {
+      let requiredFields = addressFields.trim().split(/\s+/);
+      fieldOrder = fieldOrder.filter(name => requiredFields.includes(name));
+    }
     if (address["street-address"]) {
       address["-moz-street-address-one-line"] = this.toOneLineAddress(
         address["street-address"]
       );
     }
     for (const fieldName of fieldOrder) {
       let string = address[fieldName];
       if (string) {
         parts.push(string);
       }
-      if (parts.length == 2) {
+      if (parts.length == 2 && !addressFields) {
         break;
       }
     }
     return parts.join(", ");
   },
 
   toOneLineAddress(address, delimiter = "\n") {
     let array = typeof address == "string" ? address.split(delimiter) : address;