Bug 1477699 - Show a generic error message when a merchant-supplied error message isn't present. r?mattn
MozReview-Commit-ID: Dn4mnvzunVd
--- 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");