Bug 1429189 - Show shipping address errors on the summary screen. r=mattn

MozReview-Commit-ID: LaXrvWliWna

--HG--
extra : rebase_source : 6b0639a39a92192dc0c4cbc9392d97e16717adfc
This commit is contained in:
Jared Wein 2018-02-21 14:16:35 -08:00
Родитель d14436478f
Коммит 66a1567f22
9 изменённых файлов: 217 добавлений и 7 удалений

Просмотреть файл

@ -108,6 +108,9 @@ var paymentDialogWrapper = {
if (!requestId || typeof(requestId) != "string") {
throw new Error("Invalid PaymentRequest ID");
}
// The Request object returned by the Payment Service is live and
// will automatically get updated if event.updateWith is used.
this.request = paymentSrv.getPaymentRequestById(requestId);
if (!this.request) {
@ -250,6 +253,19 @@ var paymentDialogWrapper = {
});
},
updateRequest() {
// There is no need to update this.request since the object is live
// and will automatically get updated if event.updateWith is used.
let requestSerialized = this._serializeRequest(this.request);
this.mm.sendAsyncMessage("paymentChromeToContent", {
messageType: "updateState",
data: {
request: requestSerialized,
},
});
},
/**
* Recursively convert and filter input to the subset of data types supported by JSON
*

Просмотреть файл

@ -80,7 +80,13 @@ PaymentUIService.prototype = {
},
updatePayment(requestId) {
let dialog = this.findDialog(requestId);
this.log.debug("updatePayment:", requestId);
if (!dialog) {
this.log.error("updatePayment: no dialog found");
return;
}
dialog.paymentDialogWrapper.updateRequest();
},
// other helper methods
@ -90,17 +96,25 @@ PaymentUIService.prototype = {
* @returns {boolean} whether the specified dialog was closed.
*/
closeDialog(requestId) {
let win = this.findDialog(requestId);
if (!win) {
return false;
}
this.log.debug(`closing: ${win.name}`);
win.close();
return true;
},
findDialog(requestId) {
let enu = Services.wm.getEnumerator(null);
let win;
while ((win = enu.getNext())) {
if (win.name == `${this.REQUEST_ID_PREFIX}${requestId}`) {
this.log.debug(`closing: ${win.name}`);
win.close();
return true;
return win;
}
}
return false;
return null;
},
requestIdForWindow(window) {

Просмотреть файл

@ -32,6 +32,7 @@ class PaymentDialog extends PaymentStateSubscriberMixin(HTMLElement) {
this._orderDetailsOverlay = contents.querySelector("#order-details-overlay");
this._shippingRequestedEls = contents.querySelectorAll(".shippingRequested");
this._errorText = contents.querySelector("#error-text");
this._disabledOverlay = contents.getElementById("disabled-overlay");
@ -178,14 +179,16 @@ class PaymentDialog extends PaymentStateSubscriberMixin(HTMLElement) {
render(state) {
let request = state.request;
let paymentDetails = request.paymentDetails;
this._hostNameEl.textContent = request.topLevelPrincipal.URI.displayHost;
let totalItem = request.paymentDetails.totalItem;
let totalItem = paymentDetails.totalItem;
let totalAmountEl = this.querySelector("#total > currency-amount");
totalAmountEl.value = totalItem.amount.value;
totalAmountEl.currency = totalItem.amount.currency;
this._orderDetailsOverlay.hidden = !state.orderDetailsShowing;
this._errorText.textContent = paymentDetails.error;
for (let element of this._shippingRequestedEls) {
element.hidden = !request.paymentOptions.requestShipping;
}

Просмотреть файл

@ -71,6 +71,7 @@
<shipping-option-picker class="shippingRequested"></shipping-option-picker>
<div><label>&paymentMethodsLabel;</label></div>
<payment-method-picker selected-state-key="selectedPaymentCard"></payment-method-picker>
<div id="error-text"></div>
</section>
<footer id="controls-container">

Просмотреть файл

@ -36,6 +36,25 @@ this.PaymentTestUtils = {
return true;
},
updateWith: async ({eventName, details}) => {
/* globals ok */
if (details.error &&
(!details.shippingOptions || details.shippingOptions.length)) {
ok(false, "Need to clear the shipping options to show error text");
}
if (!details.total) {
ok(false, "`total: { label, amount: { value, currency } }` is required for updateWith");
}
content[eventName + "Promise"] =
new Promise(resolve => {
content.rq.addEventListener(eventName, event => {
event.updateWith(details);
resolve();
}, {once: true});
});
},
/**
* Create a new payment request and cache it as `rq`.
*
@ -67,7 +86,7 @@ this.PaymentTestUtils = {
DialogContentTasks: {
isElementVisible: selector => {
let element = content.document.querySelector(selector);
return !element.hidden;
return element.getBoundingClientRect().height > 0;
},
getShippingOptions: () => {
@ -87,6 +106,14 @@ this.PaymentTestUtils = {
};
},
getErrorDetails: () => {
let doc = content.document;
let errorText = doc.querySelector("#error-text");
return {
text: errorText.textContent,
};
},
selectShippingAddressByCountry: country => {
let doc = content.document;
let addressPicker =
@ -268,4 +295,42 @@ this.PaymentTestUtils = {
requestShipping: true,
},
},
Addresses: {
TimBL: {
"given-name": "Timothy",
"additional-name": "John",
"family-name": "Berners-Lee",
organization: "World Wide Web Consortium",
"street-address": "32 Vassar Street\nMIT Room 32-G524",
"address-level2": "Cambridge",
"address-level1": "MA",
"postal-code": "02139",
country: "US",
tel: "+16172535702",
email: "timbl@example.org",
},
TimBL2: {
"given-name": "Timothy",
"additional-name": "John",
"family-name": "Berners-Lee",
organization: "World Wide Web Consortium",
"street-address": "1 Pommes Frittes Place",
"address-level2": "Berlin",
"address-level1": "BE",
"postal-code": "02138",
country: "DE",
tel: "+16172535702",
email: "timbl@example.org",
},
},
BasicCards: {
JohnDoe: {
"cc-exp-month": 1,
"cc-exp-year": 9999,
"cc-name": "John Doe",
"cc-number": "999999999999",
},
},
};

Просмотреть файл

@ -12,6 +12,7 @@ support-files =
[browser_request_serialization.js]
[browser_request_shipping.js]
[browser_request_summary.js]
[browser_shippingaddresschange_error.js]
[browser_show_dialog.js]
skip-if = os == 'win' && debug # bug 1418385
[browser_total.js]

Просмотреть файл

@ -0,0 +1,93 @@
"use strict";
add_task(addSampleAddressesAndBasicCard);
add_task(async function test_show_error_on_addresschange() {
await BrowserTestUtils.withNewTab({
gBrowser,
url: BLANK_PAGE_URL,
}, async browser => {
let dialogReadyPromise = waitForWidgetReady();
// start by creating a PaymentRequest, and show it
await ContentTask.spawn(browser,
{
methodData: [PTU.MethodData.basicCard],
details: PTU.Details.twoShippingOptions,
options: PTU.Options.requestShippingOption,
},
PTU.ContentTasks.createAndShowRequest);
// get a reference to the UI dialog and the requestId
let [win] = await Promise.all([getPaymentWidget(), dialogReadyPromise]);
ok(win, "Got payment widget");
let requestId = paymentUISrv.requestIdForWindow(win);
ok(requestId, "requestId should be defined");
is(win.closed, false, "dialog should not be closed");
let frame = await getPaymentFrame(win);
ok(frame, "Got payment frame");
info("setting up the event handler for shippingoptionchange");
let EXPECTED_ERROR_TEXT = "Cannot ship with option 1 on days that end with Y";
await ContentTask.spawn(browser, {
eventName: "shippingoptionchange",
details: {
error: EXPECTED_ERROR_TEXT,
shippingOptions: [],
total: {
label: "Grand total is!!!!!: ",
amount: {
value: "12",
currency: "USD",
},
},
},
}, PTU.ContentTasks.updateWith);
await spawnPaymentDialogTask(frame,
PTU.DialogContentTasks.selectShippingOptionById,
"1");
info("awaiting the shippingoptionchange event");
await ContentTask.spawn(browser, {
eventName: "shippingoptionchange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
let errors = await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getErrorDetails);
is(errors.text, EXPECTED_ERROR_TEXT, "Error text should be present on dialog");
let errorsVisible =
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.isElementVisible, "#error-text");
ok(errorsVisible, "Error text should be visible");
info("setting up the event handler for shippingaddresschange");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
details: {
error: "",
shippingOptions: PTU.Details.twoShippingOptions.shippingOptions,
total: {
label: "Grand total is now: ",
amount: {
value: "24",
currency: "USD",
},
},
},
}, PTU.ContentTasks.updateWith);
await spawnPaymentDialogTask(frame,
PTU.DialogContentTasks.selectShippingAddressByCountry,
"DE");
info("awaiting the shippingaddresschange event");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
errors = await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getErrorDetails);
is(errors.text, "", "Error text should not be present on dialog");
errorsVisible =
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.isElementVisible, "#error-text");
ok(!errorsVisible, "Error text should not be visible");
info("clicking cancel");
spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
});
});

Просмотреть файл

@ -153,7 +153,7 @@ add_task(async function test_show_completePayment() {
let frame = await getPaymentFrame(win);
ContentTask.spawn(browser, {
await ContentTask.spawn(browser, {
eventName: "shippingoptionchange",
}, PTU.ContentTasks.promisePaymentRequestEvent);

Просмотреть файл

@ -132,6 +132,23 @@ function spawnTaskInNewDialog(requestId, contentTaskFn, args = null) {
});
}
async function addSampleAddressesAndBasicCard() {
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
(subject, data) => data == "add");
profileStorage.addresses.add(PTU.Addresses.TimBL);
await onChanged;
onChanged = TestUtils.topicObserved("formautofill-storage-changed",
(subject, data) => data == "add");
profileStorage.addresses.add(PTU.Addresses.TimBL2);
await onChanged;
onChanged = TestUtils.topicObserved("formautofill-storage-changed",
(subject, data) => data == "add");
profileStorage.creditCards.add(PTU.BasicCards.JohnDoe);
await onChanged;
}
/**
* Open a merchant tab with the given merchantTaskFn to create a PaymentRequest
* and then open the associated PaymentRequest dialog in a new tab and run the