Bug 1447777 - Move state.completionState to state.request.completeStatus. r?MattN draft
authorSam Foster <sfoster@mozilla.com>
Thu, 19 Jul 2018 19:45:58 -0700
changeset 821152 4bd5ccd360f0ba8eeae30a92c7e7d2cc51836cde
parent 821151 6eec814dea789707d04f42bbb01097d44532e2a9
child 821153 a98fff8a950e64ccb2c0a0b4c6ca66aa1e621e7a
push id117018
push userbmo:sfoster@mozilla.com
push dateSat, 21 Jul 2018 04:05:10 +0000
reviewersMattN
bugs1447777
milestone63.0a1
Bug 1447777 - Move state.completionState to state.request.completeStatus. r?MattN * Spot-fix order details test to clone request before modifying it MozReview-Commit-ID: AXjI1veRSk9
browser/components/payments/res/containers/payment-dialog.js
browser/components/payments/res/debugging.js
browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js
browser/components/payments/res/paymentRequest.css
browser/components/payments/test/mochitest/test_order_details.html
browser/components/payments/test/mochitest/test_payer_address_picker.html
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
@@ -199,28 +199,32 @@ export default class PaymentDialog exten
       this.requestStore.setState({
         selectedPayerAddress: Object.keys(addresses)[0] || null,
       });
     }
   }
 
   _renderPayButton(state) {
     this._payButton.disabled = state.changesPrevented;
-    switch (state.completionState) {
+    let completeStatus = state.request.completeStatus;
+    switch (completeStatus) {
       case "initial":
       case "processing":
       case "success":
       case "fail":
       case "unknown":
         break;
+      case "":
+        completeStatus = "initial";
+        break;
       default:
-        throw new Error("Invalid completionState");
+        throw new Error(`Invalid completeStatus: ${completeStatus}`);
     }
 
-    this._payButton.textContent = this._payButton.dataset[state.completionState + "Label"];
+    this._payButton.textContent = this._payButton.dataset[completeStatus + "Label"];
   }
 
   stateChangeCallback(state) {
     super.stateChangeCallback(state);
 
     // Don't dispatch change events for initial selectedShipping* changes at initialization
     // if requestShipping is false.
     if (state.request.paymentOptions.requestShipping) {
@@ -296,23 +300,19 @@ export default class PaymentDialog exten
     this._payerAddressPicker.dataset.editAddressTitle = this.dataset.payerTitleEdit;
 
     this._renderPayButton(state);
 
     for (let page of this._mainContainer.querySelectorAll(":scope > .page")) {
       page.hidden = state.page.id != page.id;
     }
 
-    let {
-      changesPrevented,
-      completionState,
-    } = state;
-    if (changesPrevented) {
+    if (state.changesPrevented) {
       this.setAttribute("changes-prevented", "");
     } else {
       this.removeAttribute("changes-prevented");
     }
-    this.setAttribute("completion-state", completionState);
-    this._disabledOverlay.hidden = !changesPrevented;
+    this.setAttribute("complete-status", request.completeStatus);
+    this._disabledOverlay.hidden = !state.changesPrevented;
   }
 }
 
 customElements.define("payment-dialog", PaymentDialog);
--- a/browser/components/payments/res/debugging.js
+++ b/browser/components/payments/res/debugging.js
@@ -402,43 +402,48 @@ let buttonActions = {
       region: "Can only ship to regions that start with M",
     };
     requestStore.setState({
       request,
     });
   },
 
   setStateDefault() {
-    requestStore.setState({
-      completionState: "initial",
+    let request = Object.assign({}, requestStore.getState().request, {
+      completeStatus: "initial",
     });
+    requestStore.setState({ request });
   },
 
   setStateProcessing() {
-    requestStore.setState({
-      completionState: "processing",
+    let request = Object.assign({}, requestStore.getState().request, {
+      completeStatus: "processing",
     });
+    requestStore.setState({ request });
   },
 
   setStateSuccess() {
-    requestStore.setState({
-      completionState: "success",
+    let request = Object.assign({}, requestStore.getState().request, {
+      completeStatus: "success",
     });
+    requestStore.setState({ request });
   },
 
   setStateFail() {
-    requestStore.setState({
-      completionState: "fail",
+    let request = Object.assign({}, requestStore.getState().request, {
+      completeStatus: "fail",
     });
+    requestStore.setState({ request });
   },
 
   setStateUnknown() {
-    requestStore.setState({
-      completionState: "unknown",
+    let request = Object.assign({}, requestStore.getState().request, {
+      completeStatus: "unknown",
     });
+    requestStore.setState({ request });
   },
 };
 
 window.addEventListener("click", function onButtonClick(evt) {
   let id = evt.target.id;
   if (!id || typeof(buttonActions[id]) != "function") {
     return;
   }
--- a/browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js
+++ b/browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js
@@ -8,17 +8,16 @@ import PaymentsStore from "../PaymentsSt
  * A mixin for a custom element to observe store changes to information about a payment request.
  */
 
 /**
  * State of the payment request dialog.
  */
 export let requestStore = new PaymentsStore({
   changesPrevented: false,
-  completionState: "initial",
   orderDetailsShowing: false,
   "basic-card-page": {
     guid: null,
     // preserveFieldValues: true,
   },
   "address-page": {
     guid: null,
     title: "",
@@ -28,16 +27,17 @@ export let requestStore = new PaymentsSt
   page: {
     id: "payment-summary",
     previousId: null,
     // onboardingWizard: true,
     // error: "",
     // selectedStateKey: "",
   },
   request: {
+    completeStatus: "initial",
     tabId: null,
     topLevelPrincipal: {URI: {displayHost: null}},
     requestId: null,
     paymentMethods: [],
     paymentDetails: {
       id: null,
       totalItem: {label: null, amount: {currency: null, value: 0}},
       displayItems: [],
--- a/browser/components/payments/res/paymentRequest.css
+++ b/browser/components/payments/res/paymentRequest.css
@@ -130,20 +130,20 @@ payment-dialog #pay::before {
   content: url(chrome://browser/skin/connection-secure.svg);
   fill: currentColor;
   height: 16px;
   margin-right: 0.5em;
   vertical-align: text-bottom;
   width: 16px;
 }
 
-payment-dialog[changes-prevented][completion-state="fail"] #pay,
-payment-dialog[changes-prevented][completion-state="unknown"] #pay,
-payment-dialog[changes-prevented][completion-state="processing"] #pay,
-payment-dialog[changes-prevented][completion-state="success"] #pay {
+payment-dialog[changes-prevented][complete-status="fail"] #pay,
+payment-dialog[changes-prevented][complete-status="unknown"] #pay,
+payment-dialog[changes-prevented][complete-status="processing"] #pay,
+payment-dialog[changes-prevented][complete-status="success"] #pay {
   /* Show the pay button above #disabled-overlay */
   position: relative;
   z-index: 1;
 }
 
 #cancel {
   margin-left: auto;
 }
--- a/browser/components/payments/test/mochitest/test_order_details.html
+++ b/browser/components/payments/test/mochitest/test_order_details.html
@@ -122,74 +122,69 @@ add_task(async function test_list_popula
   await asyncElementRendered();
 
   is(orderDetails.mainItemsList.childElementCount, 2, "main list has correct # children");
   is(orderDetails.footerItemsList.childElementCount, 1, "footer list has correct # children");
 });
 
 add_task(async function test_additionalDisplayItems() {
   setup();
-  let state = requestStore.getState();
-  let request = state.request;
-  let paymentDetails = request.paymentDetails;
-
-  paymentDetails.modifiers = [{
-    additionalDisplayItems: [
-      {
-        label: "Card fee",
-        amount: { currency: "USD", value: "1.50" },
+  let request = Object.assign({}, requestStore.getState().request);
+  request.paymentDetails = Object.assign({}, request.paymentDetails, {
+    modifiers: [{
+      additionalDisplayItems: [
+        {
+          label: "Card fee",
+          amount: { currency: "USD", value: "1.50" },
+        },
+      ],
+      supportedMethods: "basic-card",
+      total: {
+        label: "Total due",
+        amount: { currency: "USD", value: "3.50" },
       },
-    ],
-    supportedMethods: "basic-card",
-    total: {
-      label: "Total due",
-      amount: { currency: "USD", value: "3.50" },
-    },
-  }];
-
-  Object.assign(request, { paymentDetails });
-  requestStore.setState(state);
+    }],
+  });
+  requestStore.setState({ request });
   await asyncElementRendered();
 
   is(orderDetails.mainItemsList.childElementCount, 0,
      "main list added 0 children from additionalDisplayItems");
   is(orderDetails.footerItemsList.childElementCount, 1,
      "footer list added children from additionalDisplayItems");
 });
 
 
 add_task(async function test_total() {
   setup();
-  let request = requestStore.getState().request;
-  let paymentDetails = request.paymentDetails;
-  paymentDetails.totalItem = { label: "foo", amount: { currency: "JPY", value: "5" }};
-
-  Object.assign(request, { paymentDetails });
+  let request = Object.assign({}, requestStore.getState().request);
+  request.paymentDetails = Object.assign({}, request.paymentDetails, {
+    totalItem: { label: "foo", amount: { currency: "JPY", value: "5" }},
+  });
   requestStore.setState({ request });
   await asyncElementRendered();
 
   is(orderDetails.totalAmountElem.value, "5", "total amount gets updated");
   is(orderDetails.totalAmountElem.currency, "JPY", "total currency gets updated");
 });
 
 add_task(async function test_modified_total() {
   setup();
-  let state = requestStore.getState();
-  let request = state.request;
-  let paymentDetails = request.paymentDetails;
-  paymentDetails.totalItem = { label: "foo", amount: { currency: "JPY", value: "5" }};
-  paymentDetails.modifiers = [{
-    supportedMethods: "basic-card",
-    total: {
-      label: "Total due",
-      amount: { currency: "USD", value: "3.5" },
-    },
-  }];
-  Object.assign(request, { paymentDetails });
-  requestStore.setState(state);
+  let request = Object.assign({}, requestStore.getState().request);
+  request.paymentDetails = Object.assign({}, request.paymentDetails, {
+    totalItem: { label: "foo", amount: { currency: "JPY", value: "5" }},
+    modifiers: [{
+      supportedMethods: "basic-card",
+      total: {
+        label: "Total due",
+        amount: { currency: "USD", value: "3.5" },
+      },
+    }],
+  });
+  requestStore.setState({request});
   await asyncElementRendered();
 
   is(orderDetails.totalAmountElem.value, "3.5", "total amount uses modifier total");
   is(orderDetails.totalAmountElem.currency, "USD", "total currency uses modifier currency");
 });
 
 </script>
 
--- a/browser/components/payments/test/mochitest/test_payer_address_picker.html
+++ b/browser/components/payments/test/mochitest/test_payer_address_picker.html
@@ -127,19 +127,20 @@ add_task(async function setup_once() {
     let imported = document.importNode(template, true);
     displayEl.appendChild(imported);
   }
 
   elDialog = new PaymentDialog();
   displayEl.appendChild(elDialog);
   elPicker = elDialog.querySelector("address-picker.payer-related");
 
-  initialState = Object.assign({}, elDialog.requestStore.getState(), {
+  let {request} = elDialog.requestStore.getState();
+  initialState = Object.assign({}, {
     changesPrevented: false,
-    completionState: "initial",
+    request: Object.assign({}, request, { completeStatus: "initial" }),
     orderDetailsShowing: false,
   });
 });
 
 async function setup() {
   // reset the store back to a known, default state
   elDialog.requestStore.setState(deepClone(initialState));
   await asyncElementRendered();
--- a/browser/components/payments/test/mochitest/test_payment_dialog.html
+++ b/browser/components/payments/test/mochitest/test_payment_dialog.html
@@ -31,17 +31,17 @@ Test the payment-dialog custom element
 /** Test the payment-dialog element **/
 
 /* global sinon */
 
 import PaymentDialog from "../../res/containers/payment-dialog.js";
 
 let el1;
 
-let completionStates = [
+let completeStatuses = [
     ["processing", "Processing"],
     ["success", "Done"],
     ["fail", "Fail"],
     ["unknown", "Unknown"],
 ];
 
 /* test that:
   the view-all-items button exists
@@ -65,19 +65,20 @@ add_task(async function setup_once() {
   el1 = new PaymentDialog();
   displayEl.appendChild(el1);
 
   sinon.spy(el1, "render");
   sinon.spy(el1, "stateChangeCallback");
 });
 
 async function setup() {
+  let {request} = el1.requestStore.getState();
   await el1.requestStore.setState({
     changesPrevented: false,
-    completionState: "initial",
+    request: Object.assign({}, request, {completeStatus: "initial"}),
     orderDetailsShowing: false,
   });
 
   el1.render.reset();
   el1.stateChangeCallback.reset();
 }
 
 add_task(async function test_initialState() {
@@ -139,44 +140,45 @@ add_task(async function test_changesPrev
   is(state.changesPrevented, false, "changesPrevented is initially false");
   let disabledOverlay = document.getElementById("disabled-overlay");
   ok(disabledOverlay.hidden, "Overlay should initially be hidden");
   await el1.requestStore.setState({changesPrevented: true});
   await asyncElementRendered();
   ok(!disabledOverlay.hidden, "Overlay should prevent changes");
 });
 
-add_task(async function test_completionState() {
+add_task(async function test_completeStatus() {
   await setup();
-  let state = el1.requestStore.getState();
-  is(state.completionState, "initial", "completionState is initially initial");
+  let {request} = el1.requestStore.getState();
+  is(request.completeStatus, "initial", "completeStatus is initially initial");
   let payButton = document.getElementById("pay");
   is(payButton.textContent, "Pay", "Check default label");
   ok(!payButton.disabled, "Button is enabled");
-  for (let [completionState, label] of completionStates) {
-    await el1.requestStore.setState({completionState});
+  for (let [completeStatus, label] of completeStatuses) {
+    request.completeStatus = completeStatus;
+    await el1.requestStore.setState({request});
     await asyncElementRendered();
     is(payButton.textContent, label, "Check payButton label");
     ok(!payButton.disabled, "Button is still enabled");
   }
 });
 
-add_task(async function test_completionStateChangesPrevented() {
+add_task(async function test_completeStatusChangesPrevented() {
   await setup();
   let state = el1.requestStore.getState();
-  is(state.completionState, "initial", "completionState is initially initial");
+  is(state.request.completeStatus, "initial", "completeStatus is initially initial");
   is(state.changesPrevented, false, "changesPrevented is initially false");
   let payButton = document.getElementById("pay");
   is(payButton.textContent, "Pay", "Check default label");
   ok(!payButton.disabled, "Button is enabled");
 
-  for (let [completionState, label] of completionStates) {
+  for (let [status, label] of completeStatuses) {
     await el1.requestStore.setState({
       changesPrevented: true,
-      completionState,
+      request: Object.assign(state.request, { completeStatus: status }),
     });
     await asyncElementRendered();
     is(payButton.textContent, label, "Check payButton label");
     ok(payButton.disabled, "Button is disabled");
     let rect = payButton.getBoundingClientRect();
     let visibleElement =
       document.elementFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
     ok(payButton === visibleElement, "Pay button is on top of the overlay");