зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1495549 - Clear paymentMethod errors when the paymentMethod changes. r=jaws
Differential Revision: https://phabricator.services.mozilla.com/D13451 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
b82e3514a4
Коммит
865adcf2a7
|
@ -154,6 +154,20 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the selectedPaymentCard or its relevant properties or billingAddress are changed.
|
||||
* @param {string} selectedPaymentCardGUID
|
||||
*/
|
||||
changePaymentMethod(selectedPaymentCardGUID) {
|
||||
// Clear paymentMethod merchant errors when the paymentMethod or billingAddress changes.
|
||||
let request = Object.assign({}, this.requestStore.getState().request);
|
||||
request.paymentDetails = Object.assign({}, request.paymentDetails);
|
||||
request.paymentDetails.paymentMethodErrors = null;
|
||||
this.requestStore.setState({request});
|
||||
|
||||
// TODO: Bug 1477113 - Dispatch paymentmethodchange
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the selectedPayerAddress or its relevant properties are changed.
|
||||
* @param {string} payerAddressGUID
|
||||
|
@ -216,6 +230,7 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
|
|||
*/
|
||||
async setStateFromParent(state) { // eslint-disable-line complexity
|
||||
let oldAddresses = paymentRequest.getAddresses(this.requestStore.getState());
|
||||
let oldBasicCards = paymentRequest.getBasicCards(this.requestStore.getState());
|
||||
if (state.request) {
|
||||
state = this._updateCompleteStatus(state);
|
||||
}
|
||||
|
@ -269,9 +284,28 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
|
|||
}
|
||||
}
|
||||
|
||||
let basicCards = paymentRequest.getBasicCards(state);
|
||||
let oldPaymentMethod = selectedPaymentCard && oldBasicCards[selectedPaymentCard];
|
||||
let paymentMethod = selectedPaymentCard && basicCards[selectedPaymentCard];
|
||||
if (oldPaymentMethod && paymentMethod.guid == oldPaymentMethod.guid &&
|
||||
paymentMethod.timeLastModified != oldPaymentMethod.timeLastModified) {
|
||||
delete this._cachedState.selectedPaymentCard;
|
||||
} else {
|
||||
// Changes to the billing address record don't change the `timeLastModified`
|
||||
// on the card record so we have to check for changes to the address separately.
|
||||
|
||||
let billingAddressGUID = paymentMethod && paymentMethod.billingAddressGUID;
|
||||
let billingAddress = billingAddressGUID && addresses[billingAddressGUID];
|
||||
let oldBillingAddress = billingAddressGUID && oldAddresses[billingAddressGUID];
|
||||
|
||||
if (oldBillingAddress && billingAddress &&
|
||||
billingAddress.timeLastModified != oldBillingAddress.timeLastModified) {
|
||||
delete this._cachedState.selectedPaymentCard;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure `selectedPaymentCard` never refers to a deleted payment card and refers
|
||||
// to a payment card if one exists.
|
||||
let basicCards = paymentRequest.getBasicCards(state);
|
||||
if (!basicCards[selectedPaymentCard]) {
|
||||
// Determining the initial selection is tracked in bug 1455789
|
||||
this.requestStore.setState({
|
||||
|
@ -398,6 +432,10 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
|
|||
}
|
||||
}
|
||||
|
||||
if (state.selectedPaymentCard != this._cachedState.selectedPaymentCard) {
|
||||
this.changePaymentMethod(state.selectedPaymentCard);
|
||||
}
|
||||
|
||||
if (this._isPayerRequested(state.request.paymentOptions)) {
|
||||
if (state.selectedPayerAddress != this._cachedState.selectedPayerAddress) {
|
||||
this.changePayerAddress(state.selectedPayerAddress);
|
||||
|
@ -406,6 +444,7 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
|
|||
|
||||
this._cachedState.selectedShippingAddress = state.selectedShippingAddress;
|
||||
this._cachedState.selectedShippingOption = state.selectedShippingOption;
|
||||
this._cachedState.selectedPaymentCard = state.selectedPaymentCard;
|
||||
this._cachedState.selectedPayerAddress = state.selectedPayerAddress;
|
||||
}
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ var PaymentTestUtils = {
|
|||
let {requestStore} = Cu.waiveXrays(content.document.querySelector("payment-dialog"));
|
||||
let {page} = requestStore.getState();
|
||||
let button = content.document.querySelector(`#${page.id} button.primary`);
|
||||
ok(!button.disabled, "Primary button should not be disabled when clicking it");
|
||||
ok(!button.disabled, `#${page.id} primary button should not be disabled when clicking it`);
|
||||
button.click();
|
||||
},
|
||||
|
||||
|
@ -260,7 +260,15 @@ var PaymentTestUtils = {
|
|||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
completePayment: () => {
|
||||
completePayment: async () => {
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
|
||||
await PTU.DialogContentUtils.waitForState(content, (state) => {
|
||||
return state.page.id == "payment-summary";
|
||||
}, "Wait for change to payment-summary before clicking Pay");
|
||||
|
||||
let button = content.document.getElementById("pay");
|
||||
ok(!button.disabled, "Pay button should not be disabled when clicking it");
|
||||
button.click();
|
||||
|
|
|
@ -7,15 +7,19 @@
|
|||
async function setup() {
|
||||
await setupFormAutofillStorage();
|
||||
await cleanupFormAutofillStorage();
|
||||
// add 2 addresses and a card to avoid the FTU sequence and test address errors
|
||||
// add 2 addresses and 2 cards to avoid the FTU sequence and test address errors
|
||||
let prefilledGuids = await addSampleAddressesAndBasicCard(
|
||||
[PTU.Addresses.TimBL, PTU.Addresses.TimBL2],
|
||||
[PTU.BasicCards.JohnDoe]);
|
||||
[PTU.BasicCards.JaneMasterCard, PTU.BasicCards.JohnDoe]);
|
||||
|
||||
info("associating the card with a billing address");
|
||||
info("associating card1 with a billing address");
|
||||
await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
|
||||
billingAddressGUID: prefilledGuids.address1GUID,
|
||||
}, true);
|
||||
info("associating card2 with a billing address");
|
||||
await formAutofillStorage.creditCards.update(prefilledGuids.card2GUID, {
|
||||
billingAddressGUID: prefilledGuids.address1GUID,
|
||||
}, true);
|
||||
|
||||
return prefilledGuids;
|
||||
}
|
||||
|
@ -336,3 +340,204 @@ add_task(async function test_retry_with_payerErrors() {
|
|||
await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_retry_with_paymentMethodErrors() {
|
||||
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
|
||||
todo(false, "Cannot test OS key store login on official builds.");
|
||||
return;
|
||||
}
|
||||
let prefilledGuids = 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,
|
||||
merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
|
||||
});
|
||||
|
||||
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.setSecurityCode, {
|
||||
securityCode: "123",
|
||||
});
|
||||
|
||||
info("clicking the button to try pay the 1st time");
|
||||
await loginAndCompletePayment(frame);
|
||||
|
||||
let retryUpdatePromise = spawnPaymentDialogTask(frame, async function checkDialog() {
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
|
||||
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
|
||||
return request.completeStatus === "processing";
|
||||
}, "Wait for completeStatus from pay button click");
|
||||
|
||||
is(state.request.completeStatus, "processing", "Check completeStatus is processing");
|
||||
|
||||
is(state.request.paymentDetails.paymentMethodErrors, null,
|
||||
"Check no paymentMethod errors are present");
|
||||
ok(state.changesPrevented, "Changes prevented");
|
||||
|
||||
state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
|
||||
return request.completeStatus === "";
|
||||
}, "Wait for completeStatus from DOM update");
|
||||
|
||||
is(state.request.completeStatus, "", "Check completeStatus");
|
||||
is(state.request.paymentDetails.paymentMethodErrors.cardSecurityCode,
|
||||
"Your CVV is incorrect",
|
||||
"Check cardSecurityCode error string in state");
|
||||
|
||||
ok(!state.changesPrevented, "Changes no longer prevented");
|
||||
is(state.page.id, "payment-summary", "Check still on payment-summary");
|
||||
|
||||
todo(content.document.querySelector("#payment-summary").innerText
|
||||
.includes("Your CVV is incorrect"),
|
||||
"Bug 1491815: Check error visibility on summary page");
|
||||
todo(content.document.getElementById("pay").disabled,
|
||||
"Bug 1491815: Pay button should be disabled until the field error is addressed");
|
||||
});
|
||||
|
||||
// Add a handler to retry the payment above.
|
||||
info("Tell merchant page to retry with a cardSecurityCode error string");
|
||||
let retryPromise = ContentTask.spawn(browser,
|
||||
{
|
||||
delayMs: 1000,
|
||||
validationErrors: {
|
||||
paymentMethod: {
|
||||
cardSecurityCode: "Your CVV is incorrect",
|
||||
},
|
||||
},
|
||||
},
|
||||
PTU.ContentTasks.addRetryHandler);
|
||||
|
||||
await retryUpdatePromise;
|
||||
|
||||
info("Changing to a different card to clear the error");
|
||||
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.selectPaymentOptionByGuid,
|
||||
prefilledGuids.card1GUID);
|
||||
|
||||
info("Tell merchant page to retry with a billing postalCode error string");
|
||||
let retryPromise2 = ContentTask.spawn(browser,
|
||||
{
|
||||
delayMs: 1000,
|
||||
validationErrors: {
|
||||
paymentMethod: {
|
||||
billingAddress: {
|
||||
postalCode: "Your postal code isn't valid",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PTU.ContentTasks.addRetryHandler);
|
||||
|
||||
|
||||
await loginAndCompletePayment(frame);
|
||||
|
||||
await spawnPaymentDialogTask(frame, async function checkPostalCodeError() {
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
|
||||
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
|
||||
return request.completeStatus === "";
|
||||
}, "Wait for completeStatus from DOM update");
|
||||
|
||||
is(state.request.completeStatus, "", "Check completeStatus");
|
||||
is(state.request.paymentDetails.paymentMethodErrors.billingAddress.postalCode,
|
||||
"Your postal code isn't valid",
|
||||
"Check postalCode error string in state");
|
||||
ok(!state.changesPrevented, "Changes no longer prevented");
|
||||
is(state.page.id, "payment-summary", "Check still on payment-summary");
|
||||
|
||||
todo(content.document.querySelector("#payment-summary").innerText
|
||||
.includes("Your postal code isn't valid"),
|
||||
"Bug 1491815: Check error visibility on summary page");
|
||||
todo(content.document.getElementById("pay").disabled,
|
||||
"Bug 1491815: Pay button should be disabled until the field error is addressed");
|
||||
});
|
||||
|
||||
info("Changing the billingAddress postalCode to be valid without changing selectedPaymentCard");
|
||||
|
||||
await navigateToAddCardPage(frame, {
|
||||
addLinkSelector: "payment-method-picker .edit-link",
|
||||
});
|
||||
|
||||
await navigateToAddAddressPage(frame, {
|
||||
addLinkSelector: ".billingAddressRow .edit-link",
|
||||
initialPageId: "basic-card-page",
|
||||
addressPageId: "billing-address-page",
|
||||
});
|
||||
|
||||
let newPostalCode = "90210";
|
||||
await fillInBillingAddressForm(frame, { "postal-code": newPostalCode });
|
||||
|
||||
await ContentTask.spawn(browser, {
|
||||
eventName: "paymentmethodchange",
|
||||
}, PTU.ContentTasks.promisePaymentResponseEvent);
|
||||
|
||||
await submitAddressForm(frame, null, {
|
||||
isEditing: true,
|
||||
nextPageId: "basic-card-page",
|
||||
});
|
||||
|
||||
await spawnPaymentDialogTask(frame, async function checkErrorsCleared() {
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
|
||||
await PTU.DialogContentUtils.waitForState(content, (state) => {
|
||||
return state.request.paymentDetails.paymentMethodErrors == null;
|
||||
},
|
||||
"Check no paymentMethod errors are present");
|
||||
});
|
||||
|
||||
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.clickPrimaryButton);
|
||||
|
||||
await spawnPaymentDialogTask(frame, async function checkErrorsCleared() {
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
|
||||
await PTU.DialogContentUtils.waitForState(content, (state) => {
|
||||
return state.request.paymentDetails.paymentMethodErrors == null;
|
||||
},
|
||||
"Check no card errors are present after save");
|
||||
});
|
||||
|
||||
// TODO: Add an `await` here after bug 1477113.
|
||||
ContentTask.spawn(browser, {
|
||||
eventName: "paymentmethodchange",
|
||||
}, PTU.ContentTasks.awaitPaymentEventPromise);
|
||||
|
||||
await loginAndCompletePayment(frame);
|
||||
|
||||
// We can only check the retry response after the closing as it only resolves upon complete.
|
||||
let {retryException} = await retryPromise;
|
||||
ok(!retryException, "Expect no exception to be thrown when calling retry()");
|
||||
|
||||
let {retryException2} = await retryPromise2;
|
||||
ok(!retryException2, "Expect no exception to be thrown when calling retry()");
|
||||
|
||||
// Add a handler to complete the payment above.
|
||||
info("acknowledging the completion from the merchant page");
|
||||
let result = await ContentTask.spawn(browser, {}, PTU.ContentTasks.addCompletionHandler);
|
||||
|
||||
// Verify response has the expected properties
|
||||
let expectedDetails = Object.assign({
|
||||
"cc-security-code": "123",
|
||||
}, PTU.BasicCards.JaneMasterCard);
|
||||
|
||||
let expectedBillingAddress = Object.assign({}, PTU.Addresses.TimBL, {
|
||||
"postal-code": newPostalCode,
|
||||
});
|
||||
|
||||
checkPaymentMethodDetailsMatchesCard(result.response.details, expectedDetails,
|
||||
"Check response payment details");
|
||||
checkPaymentAddressMatchesStorageAddress(result.response.details.billingAddress,
|
||||
expectedBillingAddress,
|
||||
"Check response billing address");
|
||||
|
||||
await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче