Bug 1428472 - Default to the selected shipping address on the "add basic card" screen. r=jaws
MozReview-Commit-ID: Hx4AHqiTapn
--- a/toolkit/components/payments/res/PaymentsStore.js
+++ b/toolkit/components/payments/res/PaymentsStore.js
@@ -8,16 +8,17 @@
* state propagation.
*/
export default class PaymentsStore {
/**
* @param {object} [defaultState = {}] The initial state of the store.
*/
constructor(defaultState = {}) {
+ this._defaultState = Object.assign({}, defaultState);
this._state = defaultState;
this._nextNotifification = 0;
this._subscribers = new Set();
}
/**
* Get the current state as a shallow clone with a shallow freeze.
* You shouldn't modify any part of the returned state object as that would bypass notifying
@@ -25,16 +26,24 @@ export default class PaymentsStore {
*
* @returns {Object} containing the current state
*/
getState() {
return Object.freeze(Object.assign({}, this._state));
}
/**
+ * Used for testing to reset to the default state from the constructor.
+ * @returns {Promise} returned by setState.
+ */
+ async reset() {
+ return this.setState(this._defaultState);
+ }
+
+ /**
* Augment the current state with the keys of `obj` and asynchronously notify
* state subscribers. As a result, multiple synchronous state changes will lead
* to a single subscriber notification which leads to better performance and
* reduces partial state changes.
*
* @param {Object} obj The object to augment the state with. Keys in the object
* will be shallow copied with Object.assign.
*
--- a/toolkit/components/payments/res/containers/basic-card-form.js
+++ b/toolkit/components/payments/res/containers/basic-card-form.js
@@ -73,29 +73,32 @@ export default class BasicCardForm exten
this.backButton.textContent = this.dataset.backButtonLabel;
this.saveButton.textContent = this.dataset.saveButtonLabel;
let record = {};
let {
page,
savedAddresses,
savedBasicCards,
+ selectedShippingAddress,
} = state;
this.genericErrorText.textContent = page.error;
let editing = !!page.guid;
this.form.querySelector("#cc-number").disabled = editing;
// If a card is selected we want to edit it.
if (editing) {
record = savedBasicCards[page.guid];
if (!record) {
throw new Error("Trying to edit a non-existing card: " + page.guid);
}
+ } else if (selectedShippingAddress) {
+ record.billingAddressGUID = selectedShippingAddress;
}
this.formHandler.loadRecord(record, savedAddresses);
}
handleEvent(event) {
switch (event.type) {
case "click": {
--- a/toolkit/components/payments/res/containers/payment-dialog.js
+++ b/toolkit/components/payments/res/containers/payment-dialog.js
@@ -9,16 +9,17 @@ import PaymentStateSubscriberMixin from
import "../components/currency-amount.js";
import "./address-picker.js";
import "./basic-card-form.js";
import "./order-details.js";
import "./payment-method-picker.js";
import "./shipping-option-picker.js";
/* global paymentRequest */
+/* import-globals-from ../unprivileged-fallbacks.js */
/**
* <payment-dialog></payment-dialog>
*/
export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLElement) {
constructor() {
super();
@@ -116,16 +117,17 @@ export default class PaymentDialog exten
*/
setStateFromParent(state) {
let oldSavedAddresses = this.requestStore.getState().savedAddresses;
this.requestStore.setState(state);
// Check if any foreign-key constraints were invalidated.
state = this.requestStore.getState();
let {
+ request: {paymentOptions: {requestShipping: requestShipping}},
savedAddresses,
savedBasicCards,
selectedPayerAddress,
selectedPaymentCard,
selectedShippingAddress,
selectedShippingOption,
} = state;
let shippingOptions = state.request.paymentDetails.shippingOptions;
@@ -141,18 +143,23 @@ export default class PaymentDialog exten
if (oldShippingAddress &&
shippingAddress.guid == oldShippingAddress.guid &&
shippingAddress.timeLastModified != oldShippingAddress.timeLastModified) {
delete this._cachedState.selectedShippingAddress;
}
} else {
// assign selectedShippingAddress as value if it is undefined,
// or if the address it pointed to was removed from storage
+ let defaultShippingAddress = null;
+ if (requestShipping) {
+ defaultShippingAddress = Object.keys(savedAddresses)[0];
+ log.debug("selecting the default shipping address");
+ }
this.requestStore.setState({
- selectedShippingAddress: Object.keys(savedAddresses)[0] || null,
+ selectedShippingAddress: defaultShippingAddress || null,
});
}
// Ensure `selectedPaymentCard` never refers to a deleted payment card and refers
// to a payment card if one exists.
if (!savedBasicCards[selectedPaymentCard]) {
this.requestStore.setState({
selectedPaymentCard: Object.keys(savedBasicCards)[0] || null,
--- a/toolkit/components/payments/res/debugging.js
+++ b/toolkit/components/payments/res/debugging.js
@@ -305,21 +305,21 @@ let buttonActions = {
setChangesPrevented() {
requestStore.setState({
changesPrevented: true,
});
},
setRequest1() {
- requestStore.setState({request: REQUEST_1});
+ paymentDialog.setStateFromParent({request: REQUEST_1});
},
setRequest2() {
- requestStore.setState({request: REQUEST_2});
+ paymentDialog.setStateFromParent({request: REQUEST_2});
},
setRequestPayerName() {
buttonActions.setPaymentOptions();
},
setRequestPayerEmail() {
buttonActions.setPaymentOptions();
},
--- a/toolkit/components/payments/test/browser/browser_change_shipping.js
+++ b/toolkit/components/payments/test/browser/browser_change_shipping.js
@@ -138,16 +138,17 @@ add_task(async function test_address_edi
gBrowser,
url: BLANK_PAGE_URL,
}, async browser => {
let {win, frame} =
await setupPaymentDialog(browser, {
methodData: [PTU.MethodData.basicCard],
details: PTU.Details.twoShippingOptions,
merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+ options: PTU.Options.requestShippingOption,
}
);
let addressOptions =
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingAddresses);
info("initial addressOptions: " + JSON.stringify(addressOptions));
let selectedIndex = addressOptions.selectedOptionIndex;
let selectedAddressGuid = addressOptions.options[selectedIndex].guid;
@@ -191,16 +192,17 @@ add_task(async function test_address_rem
gBrowser,
url: BLANK_PAGE_URL,
}, async browser => {
let {win, frame} =
await setupPaymentDialog(browser, {
methodData: [PTU.MethodData.basicCard],
details: PTU.Details.twoShippingOptions,
merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+ options: PTU.Options.requestShippingOption,
}
);
let addressOptions =
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingAddresses);
info("initial addressOptions: " + JSON.stringify(addressOptions));
let selectedIndex = addressOptions.selectedOptionIndex;
let selectedAddressGuid = addressOptions.options[selectedIndex].guid;
--- a/toolkit/components/payments/test/mochitest/mochitest.ini
+++ b/toolkit/components/payments/test/mochitest/mochitest.ini
@@ -1,12 +1,13 @@
[DEFAULT]
prefs =
dom.webcomponents.customelements.enabled=false
support-files =
+ !/browser/extensions/formautofill/content/editCreditCard.xhtml
../../../../../browser/extensions/formautofill/content/autofillEditForms.js
../../../../../testing/modules/sinon-2.3.2.js
../../res/**
payments_common.js
skip-if = !e10s
[test_address_picker.html]
[test_basic_card_form.html]
--- a/toolkit/components/payments/test/mochitest/test_basic_card_form.html
+++ b/toolkit/components/payments/test/mochitest/test_basic_card_form.html
@@ -34,16 +34,17 @@ Test the basic-card-form element
/* import-globals-from payments_common.js */
import BasicCardForm from "../../res/containers/basic-card-form.js";
let display = document.getElementById("display");
function checkCCForm(customEl, expectedCard) {
const CC_PROPERTY_NAMES = [
+ "billingAddressGUID",
"cc-number",
"cc-name",
"cc-exp-month",
"cc-exp-year",
];
for (let propName of CC_PROPERTY_NAMES) {
let expectedVal = expectedCard[propName] || "";
is(document.getElementById(propName).value,
@@ -148,17 +149,92 @@ add_task(async function test_genericErro
display.appendChild(form);
await asyncElementRendered();
ok(!isHidden(form.genericErrorText), "Error message should be visible");
is(form.genericErrorText.textContent, "Generic Error", "Check error message");
form.remove();
});
-add_task(async function test_record() {
+add_task(async function test_add_selectedShippingAddress() {
+ let form = new BasicCardForm();
+ await form.promiseReady;
+ display.appendChild(form);
+ await asyncElementRendered();
+
+ info("have an existing card in storage");
+ let card1 = deepClone(PTU.BasicCards.JohnDoe);
+ card1.guid = "9864798564";
+ card1["cc-exp-year"] = 2011;
+
+ let address1 = deepClone(PTU.Addresses.TimBL);
+ address1.guid = "TimBLGUID";
+
+ await form.requestStore.setState({
+ page: {
+ id: "basic-card-page",
+ },
+ savedAddresses: {
+ [address1.guid]: deepClone(address1),
+ },
+ savedBasicCards: {
+ [card1.guid]: deepClone(card1),
+ },
+ selectedShippingAddress: address1.guid,
+ });
+ await asyncElementRendered();
+ checkCCForm(form, {
+ billingAddressGUID: address1.guid,
+ });
+
+ form.remove();
+ await form.requestStore.reset();
+});
+
+add_task(async function test_add_noSelectedShippingAddress() {
+ let form = new BasicCardForm();
+ await form.promiseReady;
+ display.appendChild(form);
+ await asyncElementRendered();
+
+ info("have an existing card in storage but unused");
+ let card1 = deepClone(PTU.BasicCards.JohnDoe);
+ card1.guid = "9864798564";
+ card1["cc-exp-year"] = 2011;
+
+ let address1 = deepClone(PTU.Addresses.TimBL);
+ address1.guid = "TimBLGUID";
+
+ await form.requestStore.setState({
+ page: {
+ id: "basic-card-page",
+ },
+ savedAddresses: {
+ [address1.guid]: deepClone(address1),
+ },
+ savedBasicCards: {
+ [card1.guid]: deepClone(card1),
+ },
+ selectedShippingAddress: null,
+ });
+ await asyncElementRendered();
+ checkCCForm(form, {});
+
+ info("now test with a missing selectedShippingAddress");
+ await form.requestStore.setState({
+ selectedShippingAddress: "some-missing-guid",
+ });
+ await asyncElementRendered();
+ checkCCForm(form, {});
+
+ form.remove();
+ await form.requestStore.reset();
+});
+
+add_task(async function test_edit() {
let form = new BasicCardForm();
await form.promiseReady;
display.appendChild(form);
await asyncElementRendered();
info("test year before current");
let card1 = deepClone(PTU.BasicCards.JohnDoe);
card1.guid = "9864798564";