Bug 1477699 - Show a generic error message when a merchant-supplied error message isn't present. r?mattn draft
authorJared Wein <jwein@mozilla.com>
Tue, 31 Jul 2018 15:09:58 -0400
changeset 826406 92eafccc68b89f7f0ff3a4dffbb3a151ceac81aa
parent 826027 bfeebe1b8b8309c0c73bc67b480c59784d3824b6
child 826502 bbbcb06aa678353187e42e866cce1acaf524b256
child 826503 e3a5afb3eaaed27d262c25143b3e864f5d3137b9
push id118317
push userbmo:jaws@mozilla.com
push dateFri, 03 Aug 2018 19:16:34 +0000
reviewersmattn
bugs1477699
milestone63.0a1
Bug 1477699 - Show a generic error message when a merchant-supplied error message isn't present. r?mattn MozReview-Commit-ID: Dn4mnvzunVd
browser/components/payments/res/containers/payment-dialog.js
browser/components/payments/res/paymentRequest.xhtml
browser/components/payments/test/mochitest/test_payment_dialog.html
--- a/browser/components/payments/res/containers/payment-dialog.js
+++ b/browser/components/payments/res/containers/payment-dialog.js
@@ -295,28 +295,36 @@ export default class PaymentDialog exten
 
     let shippingType = state.request.paymentOptions.shippingType || "shipping";
     this._shippingAddressPicker.dataset.addAddressTitle =
       this.dataset[shippingType + "AddressTitleAdd"];
     this._shippingAddressPicker.dataset.editAddressTitle =
       this.dataset[shippingType + "AddressTitleEdit"];
     let addressPickerLabel = this._shippingAddressPicker.dataset[shippingType + "AddressLabel"];
     this._shippingAddressPicker.setAttribute("label", addressPickerLabel);
+    let optionPickerLabel = this._shippingOptionPicker.dataset[shippingType + "OptionsLabel"];
+    this._shippingOptionPicker.setAttribute("label", optionPickerLabel);
 
     let totalItem = paymentRequest.getTotalItem(state);
     let totalAmountEl = this.querySelector("#total > currency-amount");
     totalAmountEl.value = totalItem.amount.value;
     totalAmountEl.currency = totalItem.amount.currency;
 
     // Show the total header on the address and basic card pages only during
     // on-boarding(FTU) and on the payment summary page.
     this._header.hidden = !state.page.onboardingWizard && state.page.id != "payment-summary";
 
     this._orderDetailsOverlay.hidden = !state.orderDetailsShowing;
-    this._errorText.textContent = paymentDetails.error;
+    let genericError = "";
+    if (this._shippingAddressPicker.value &&
+        (!request.paymentDetails.shippingOptions ||
+         !request.paymentDetails.shippingOptions.length)) {
+      genericError = this._errorText.dataset[shippingType + "GenericError"];
+    }
+    this._errorText.textContent = paymentDetails.error || genericError;
 
     let paymentOptions = request.paymentOptions;
     for (let element of this._shippingRelatedEls) {
       element.hidden = !paymentOptions.requestShipping;
     }
     let payerRequested = this._isPayerRequested(paymentOptions);
     for (let element of this._payerRelatedEls) {
       element.hidden = !payerRequested;
--- a/browser/components/payments/res/paymentRequest.xhtml
+++ b/browser/components/payments/res/paymentRequest.xhtml
@@ -12,16 +12,21 @@
   <!ENTITY paymentSummaryTitle        "Your Payment">
   <!ENTITY header.payTo               "Pay to">
   <!ENTITY fieldRequiredSymbol        "*">
 
   <!ENTITY shippingAddressLabel       "Shipping Address">
   <!ENTITY deliveryAddressLabel       "Delivery Address">
   <!ENTITY pickupAddressLabel         "Pickup Address">
   <!ENTITY shippingOptionsLabel       "Shipping Options">
+  <!ENTITY deliveryOptionsLabel       "Delivery Options">
+  <!ENTITY pickupOptionsLabel         "Pickup Options">
+  <!ENTITY shippingGenericError       "Can't ship to this address. Select a different address.">
+  <!ENTITY deliveryGenericError       "Can't deliver to this address. Select a different address.">
+  <!ENTITY pickupGenericError         "Can't pick up from this address. Select a different address.">
   <!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 shippingAddress.addPage.title  "Add Shipping Address">
@@ -95,17 +100,21 @@
 
   <script src="formautofill/autofillEditForms.js"></script>
 
   <script type="module" src="containers/payment-dialog.js"></script>
   <script type="module" src="paymentRequest.js"></script>
 
   <template id="payment-dialog-template">
     <header>
-      <div class="page-error" aria-live="polite"></div>
+      <div class="page-error"
+           data-shipping-generic-error="&shippingGenericError;"
+           data-delivery-generic-error="&deliveryGenericError;"
+           data-pickup-generic-error="&pickupGenericError;"
+           aria-live="polite"></div>
       <div id="total">
         <currency-amount display-code="display-code"></currency-amount>
         <div>&header.payTo; <span id="host-name"></span></div>
       </div>
       <div id="top-buttons" hidden="hidden">
         <button id="view-all" class="closed">&viewAllItems;</button>
       </div>
     </header>
@@ -117,17 +126,19 @@
                           data-add-link-label="&address.addLink.label;"
                           data-edit-link-label="&address.editLink.label;"
                           data-shipping-address-label="&shippingAddressLabel;"
                           data-delivery-address-label="&deliveryAddressLabel;"
                           data-pickup-address-label="&pickupAddressLabel;"
                           selected-state-key="selectedShippingAddress"></address-picker>
 
           <shipping-option-picker class="shipping-related"
-                                  label="&shippingOptionsLabel;"></shipping-option-picker>
+                                  data-shipping-options-label="&shippingOptionsLabel;"
+                                  data-delivery-options-label="&deliveryOptionsLabel;"
+                                  data-pickup-options-label="&pickupOptionsLabel;"></shipping-option-picker>
 
           <payment-method-picker selected-state-key="selectedPaymentCard"
                                  data-add-link-label="&basicCard.addLink.label;"
                                  data-edit-link-label="&basicCard.editLink.label;"
                                  data-cvv-placeholder="&basicCard.cvv.placeholder;"
                                  label="&paymentMethodsLabel;">
           </payment-method-picker>
           <address-picker class="payer-related"
--- a/browser/components/payments/test/mochitest/test_payment_dialog.html
+++ b/browser/components/payments/test/mochitest/test_payment_dialog.html
@@ -139,16 +139,53 @@ add_task(async function test_initial_com
 
   let payButton = document.getElementById("pay");
   is(payButton, document.querySelector(`#${page.id} button.primary`),
      "Primary button is the pay button in the initial state");
   is(payButton.textContent, "Pay", "Check default label");
   ok(payButton.disabled, "Button is disabled by default");
 });
 
+add_task(async function test_generic_errors() {
+  await setup();
+  const SHIPPING_GENERIC_ERROR = "Can't ship to that address";
+  el1._errorText.dataset.shippingGenericError = SHIPPING_GENERIC_ERROR;
+  el1.requestStore.setState({
+    savedAddresses: {
+      "48bnds6854t": {
+        "address-level1": "MI",
+        "address-level2": "Some City",
+        "country": "US",
+        "guid": "48bnds6854t",
+        "name": "Mr. Foo",
+        "postal-code": "90210",
+        "street-address": "123 Sesame Street,\nApt 40",
+        "tel": "+1 519 555-5555",
+      },
+      "68gjdh354j": {
+        "address-level1": "CA",
+        "address-level2": "Mountain View",
+        "country": "US",
+        "guid": "68gjdh354j",
+        "name": "Mrs. Bar",
+        "postal-code": "94041",
+        "street-address": "P.O. Box 123",
+        "tel": "+1 650 555-5555",
+      },
+    },
+    selectedShippingAddress: "48bnds6854t",
+  });
+  await asyncElementRendered();
+
+  let picker = el1._shippingAddressPicker;
+  ok(picker.value, "Address picker should have a selected value");
+  is(el1._errorText.textContent, SHIPPING_GENERIC_ERROR,
+     "Generic error message should be shown when no shipping options or error are provided");
+});
+
 add_task(async function test_processing_completeStatus() {
   // "processing": has overlay. Check button visibility
   await setup();
   let {request} = el1.requestStore.getState();
   // this a transition state, set when waiting for a response from the merchant page
   el1.requestStore.setState({
     changesPrevented: true,
     request: Object.assign({}, request, {completeStatus: "processing"}),
@@ -229,16 +266,44 @@ add_task(async function test_scrollPayme
   is(summaryPageBody.scrollTop, 0, "Page body not scrolled initially");
   let securityCodeInput = summaryPageBody.querySelector("payment-method-picker input");
   securityCodeInput.focus();
   await new Promise(resolve => SimpleTest.executeSoon(resolve));
   ok(summaryPageBody.scrollTop > 0, "Page body scrolled after focusing the CVV field");
   el1.parentElement.style.height = "";
 });
 
+add_task(async function test_picker_labels() {
+  await setup();
+  let picker = el1._shippingOptionPicker;
+
+  const SHIPPING_OPTIONS_LABEL = "Shipping options";
+  const DELIVERY_OPTIONS_LABEL = "Delivery options";
+  const PICKUP_OPTIONS_LABEL = "Pickup options";
+  picker.dataset.shippingOptionsLabel = SHIPPING_OPTIONS_LABEL;
+  picker.dataset.deliveryOptionsLabel = DELIVERY_OPTIONS_LABEL;
+  picker.dataset.pickupOptionsLabel = PICKUP_OPTIONS_LABEL;
+
+  for (let [shippingType, label] of [
+    ["shipping", SHIPPING_OPTIONS_LABEL],
+    ["delivery", DELIVERY_OPTIONS_LABEL],
+    ["pickup", PICKUP_OPTIONS_LABEL],
+  ]) {
+    let request = deepClone(el1.requestStore.getState().request);
+    request.paymentOptions.requestShipping = true;
+    request.paymentOptions.shippingType = shippingType;
+    await el1.requestStore.setState({ request });
+    await asyncElementRendered();
+    is(picker.labelElement.textContent, label,
+       `Label should be appropriate for ${shippingType}`);
+    info(JSON.stringify(el1.requestStore.getState(), null, 2));
+    info(picker.outerHTML);
+  }
+});
+
 add_task(async function test_disconnect() {
   await setup();
 
   el1.remove();
   await el1.requestStore.setState({orderDetailsShowing: true});
   await asyncElementRendered();
   ok(el1.stateChangeCallback.notCalled, "stateChangeCallback not called");
   ok(el1.render.notCalled, "render not called");