Bug 1483470 - Improve the test case for responding a closed PaymentRequest. r=baku
authorEden Chuang <echuang@mozilla.com>
Fri, 24 Aug 2018 11:28:50 +0200
changeset 482269 cd7292d051a05ce83b421aada6e8e0e6598cdfb9
parent 482268 13c13a8c4dd33a66ab6f623b6f9ef56ab9cc7b59
child 482270 b7248bb3f017188a9dc6bf0d0ab3e4e8699d5183
push id232
push userfmarier@mozilla.com
push dateWed, 05 Sep 2018 20:45:54 +0000
reviewersbaku
bugs1483470
milestone63.0a1
Bug 1483470 - Improve the test case for responding a closed PaymentRequest. r=baku 1. Improving the testCloseByRedirectingAfterShow. Try to call PaymentRequestService::respondPayment when the PaymentRequest is closed. 2. Adding a new test testUpdateWithRespondedPayment for the case the merchant calls PaymentRequestUpdateEvent::updateWith() and the PaymentRequest is rejected by the user.
dom/payments/test/BasiccardChromeScript.js
dom/payments/test/CleanupChromeScript.js
dom/payments/test/ClosePaymentChromeScript.js
dom/payments/test/CurrencyAmountValidationChromeScript.js
dom/payments/test/PMIValidationChromeScript.js
dom/payments/test/RequestShippingChromeScript.js
dom/payments/test/ShippingOptionsChromeScript.js
dom/payments/test/ShowPaymentChromeScript.js
dom/payments/test/UpdateErrorsChromeScript.js
dom/payments/test/mochitest.ini
dom/payments/test/simple_payment_request.html
dom/payments/test/test_cleanupPayment.html
dom/payments/test/test_closePayment.html
--- a/dom/payments/test/BasiccardChromeScript.js
+++ b/dom/payments/test/BasiccardChromeScript.js
@@ -69,16 +69,18 @@ const detailedResponseUI = {
                       "",                   // payer email
                       "");                  // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
   abortPayment: abortPaymentResponse,
   completePayment: completePaymentResponse,
   updatePayment: function(requestId) {
   },
+  closePayment: function (requestId) {
+  },
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 const simpleResponseUI = {
   showPayment: function(requestId) {
     try {
       basiccardResponseData.initData("",                 // cardholderName
                                      "4916855166538720", // cardNumber
@@ -97,16 +99,18 @@ const simpleResponseUI = {
                       "",                   // payer email
                       "");                  // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
   abortPayment: abortPaymentResponse,
   completePayment: completePaymentResponse,
   updatePayment: function(requestId) {
   },
+  closePayment: function(requestId) {
+  },
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 addMessageListener("set-detailed-ui-service", function() {
   paymentSrv.setTestingUIService(detailedResponseUI.QueryInterface(Ci.nsIPaymentUIService));
 });
 
 addMessageListener("set-simple-ui-service", function() {
deleted file mode 100644
--- a/dom/payments/test/CleanupChromeScript.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
-
-function emitTestFail(message) {
-  sendAsyncMessage("test-fail", message);
-}
-function emitTestPass(message) {
-  sendAsyncMessage("test-pass", message);
-}
-
-addMessageListener("cleanup-check", function() {
-  const paymentEnum = paymentSrv.enumerate();
-  if (paymentEnum.hasMoreElements()) {
-    emitTestFail("Non-empty PaymentRequest queue in PaymentRequestService.");
-  } else {
-    emitTestPass("Got empty PaymentRequest queue in PaymentRequestService.");
-  }
-  sendAsyncMessage("cleanup-check-complete");
-});
-
-var setPaymentNums = 0;
-
-addMessageListener("payment-num-set", function() {
-  setPaymentNums = 0;
-  for (let payment of paymentSrv.enumerate()) {
-    setPaymentNums = setPaymentNums + 1;
-  }
-  sendAsyncMessage("payment-num-set-complete");
-});
-
-addMessageListener("payment-num-check", function(expectedNumPayments) {
-  let numPayments = 0;
-  for (let payment of paymentSrv.enumerate()) {
-    numPayments = numPayments + 1;
-  }
-  if (numPayments !== expectedNumPayments + setPaymentNums) {
-    emitTestFail("Expected '" + expectedNumPayments +
-                 "' PaymentRequests in PaymentRequestService" + ", but got '" +
-                 numPayments + "'.");
-  } else {
-    emitTestPass("Got expected '" + numPayments +
-                 "' PaymentRequests in PaymentRequestService.");
-  }
-  // force cleanup PaymentRequests for clear environment to next testcase.
-  paymentSrv.cleanup();
-  sendAsyncMessage("payment-num-check-complete");
-});
-
-addMessageListener("teardown", function() {
-  paymentSrv.setTestingUIService(null);
-  sendAsyncMessage('teardown-complete');
-});
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/ClosePaymentChromeScript.js
@@ -0,0 +1,117 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+
+function emitTestFail(message) {
+  sendAsyncMessage("test-fail", message);
+}
+function emitTestPass(message) {
+  sendAsyncMessage("test-pass", message);
+}
+
+addMessageListener("close-check", function() {
+  const paymentEnum = paymentSrv.enumerate();
+  if (paymentEnum.hasMoreElements()) {
+    emitTestFail("Non-empty PaymentRequest queue in PaymentRequestService.");
+  } else {
+    emitTestPass("Got empty PaymentRequest queue in PaymentRequestService.");
+  }
+  sendAsyncMessage("close-check-complete");
+});
+
+var setPaymentNums = 0;
+
+addMessageListener("payment-num-set", function() {
+  setPaymentNums = 0;
+  const paymentEnum = paymentSrv.enumerate();
+  while (paymentEnum.hasMoreElements()) {
+    setPaymentNums = setPaymentNums + 1;
+    paymentEnum.getNext();
+  }
+  sendAsyncMessage("payment-num-set-complete");
+});
+
+addMessageListener("payment-num-check", function(expectedNumPayments) {
+  const paymentEnum = paymentSrv.enumerate();
+  let numPayments = 0;
+  while (paymentEnum.hasMoreElements()) {
+    numPayments = numPayments + 1;
+    paymentEnum.getNext();
+  }
+  if (numPayments !== expectedNumPayments + setPaymentNums) {
+    emitTestFail("Expected '" + expectedNumPayments +
+                 "' PaymentRequests in PaymentRequestService" + ", but got '" +
+                 numPayments + "'.");
+  } else {
+    emitTestPass("Got expected '" + numPayments +
+                 "' PaymentRequests in PaymentRequestService.");
+  }
+  // force cleanup PaymentRequests for clear environment to next testcase.
+  paymentSrv.cleanup();
+  sendAsyncMessage("payment-num-check-complete");
+});
+
+var respondRequestId;
+
+addMessageListener("reject-payment", (expectedError) => {
+  try {
+    const responseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
+                            createInstance(Ci.nsIGeneralResponseData);
+    responseData.initData({});
+    const showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
+                            createInstance(Ci.nsIPaymentShowActionResponse);
+    showResponse.init(respondRequestId,
+                      Ci.nsIPaymentActionResponse.PAYMENT_REJECTED,
+                      "",                 // payment method
+                      responseData,       // payment method data
+                      "",                 // payer name
+                      "",                 // payer email
+                      "");                // payer phone
+    paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
+    emitTestPass("Reject PaymentRequest successfully");
+  } catch (error) {
+    if (expectedError) {
+      if (error.name === "NS_ERROR_FAILURE") {
+        emitTestPass("Got expected NS_ERROR_FAILURE when responding a closed PaymentRequest");
+        sendAsyncMessage("reject-payment-complete");
+        return;
+      }
+    }
+    emitTestFail("Unexpected error '" + error.name +
+                 "' when reponding a closed PaymentRequest");
+  }
+  sendAsyncMessage("reject-payment-complete");
+});
+
+addMessageListener("update-payment", () => {
+  try {
+    paymentSrv.changeShippingOption(respondRequestId, "");
+    emitTestPass("Change shippingOption succefully");
+  } catch (error) {
+    emitTestFail("Unexpected error '" + error.name +
+                 "' when changing the shipping option");
+  }
+  sendAsyncMessage("update-payment-complete");
+});
+
+const DummyUIService = {
+  showPayment: (requestId => {respondRequestId = requestId}),
+  abortPayment: (requestId) => {respondRequestId = requestId},
+  completePayment: (requestId) => {respondRequestId = requestId},
+  updatePayment: (requestId) => {respondRequestId = requestId},
+  closePayment: (requestId) => {respondRequestId = requestId},
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
+};
+
+paymentSrv.setTestingUIService(DummyUIService.QueryInterface(Ci.nsIPaymentUIService));
+
+
+addMessageListener("teardown", function() {
+  paymentSrv.setTestingUIService(null);
+  sendAsyncMessage('teardown-complete');
+});
--- a/dom/payments/test/CurrencyAmountValidationChromeScript.js
+++ b/dom/payments/test/CurrencyAmountValidationChromeScript.js
@@ -21,16 +21,17 @@ const InvalidDetailsUIService = {
     ].createInstance(Ci.nsIPaymentAbortActionResponse);
     abortResponse.init(requestId, Ci.nsIPaymentActionResponse.ABORT_SUCCEEDED);
     paymentSrv.respondPayment(
       abortResponse.QueryInterface(Ci.nsIPaymentActionResponse)
     );
   },
   completePayment(requestId) {},
   updatePayment(requestId) {},
+  closePayment(requestId) {},
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 function checkLowerCaseCurrency() {
   const paymentEnum = paymentSrv.enumerate();
   if (!paymentEnum.hasMoreElements()) {
     const msg =
       "PaymentRequestService should have at least one payment request.";
--- a/dom/payments/test/PMIValidationChromeScript.js
+++ b/dom/payments/test/PMIValidationChromeScript.js
@@ -34,16 +34,18 @@ const UIService = {
                       Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
                       "https://example.com",   // payment method
                       showResponseData,           // payment method data
                       "Bill A. Pacheco",          // payer name
                       "",                         // payer email
                       "");                        // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
+  closePayment: function(requestId) {
+  },
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 function emitTestFail(message) {
   sendAsyncMessage("test-fail", message);
 }
 
 addMessageListener("set-ui-service", function() {
--- a/dom/payments/test/RequestShippingChromeScript.js
+++ b/dom/payments/test/RequestShippingChromeScript.js
@@ -66,16 +66,18 @@ const NormalUIService = {
                       Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
                       "testing-payment-method",   // payment method
                       showResponseData,           // payment method data
                       "",                         // payer name
                       "",                         // payer email
                       "");                        // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
+  closePayment: function(requestId) {
+  },
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 addMessageListener("set-normal-ui-service", function() {
   paymentSrv.setTestingUIService(NormalUIService.QueryInterface(Ci.nsIPaymentUIService));
 });
 
 addMessageListener("teardown", function() {
--- a/dom/payments/test/ShippingOptionsChromeScript.js
+++ b/dom/payments/test/ShippingOptionsChromeScript.js
@@ -69,16 +69,18 @@ const TestingUIService = {
   completePayment: function(requestId) {
     let request = paymentSrv.getPaymentRequestById(requestId);
     let completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"].
                            createInstance(Ci.nsIPaymentCompleteActionResponse);
     completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLETE_SUCCEEDED);
     paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
   updatePayment: updateRequest,
+  closePayment: function(requestId) {
+  },
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 paymentSrv.setTestingUIService(TestingUIService.QueryInterface(Ci.nsIPaymentUIService));
 
 addMessageListener("set-expected-results", function(results) {
   expectedRequestOption = results.requestResult;
   expectedUpdatedOption = results.responseResult;
--- a/dom/payments/test/ShowPaymentChromeScript.js
+++ b/dom/payments/test/ShowPaymentChromeScript.js
@@ -145,16 +145,17 @@ function updateRequest(requestId) {
   }
 }
 
 const DummyUIService = {
   showPayment: showRequest,
   abortPayment: abortRequest,
   completePayment: completeRequest,
   updatePayment: updateRequest,
+  closePayment: function(requestId) {},
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 paymentSrv.setTestingUIService(DummyUIService.QueryInterface(Ci.nsIPaymentUIService));
 
 function testShowResponseInit() {
   const showResponseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
                               createInstance(Ci.nsIGeneralResponseData);
--- a/dom/payments/test/UpdateErrorsChromeScript.js
+++ b/dom/payments/test/UpdateErrorsChromeScript.js
@@ -141,16 +141,17 @@ function updateRequest(requestId) {
   rejectShow(requestId);
 }
 
 const DummyUIService = {
   showPayment: showRequest,
   abortPayment: abortRequest,
   completePayment: completeRequest,
   updatePayment: updateRequest,
+  closePayment: function(requestId) {},
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 paymentSrv.setTestingUIService(DummyUIService.QueryInterface(Ci.nsIPaymentUIService));
 
 addMessageListener("teardown", function() {
   paymentSrv.setTestingUIService(null);
   sendAsyncMessage('teardown-complete');
--- a/dom/payments/test/mochitest.ini
+++ b/dom/payments/test/mochitest.ini
@@ -2,17 +2,17 @@
 # skip-if !e10s will be removed once non-e10s is supported
 skip-if = !e10s || !nightly_build
 scheme = https
 support-files =
   blank_page.html
   simple_payment_request.html
   echo_payment_request.html
   BasiccardChromeScript.js
-  CleanupChromeScript.js
+  ClosePaymentChromeScript.js
   ConstructorChromeScript.js
   CurrencyAmountValidationChromeScript.js
   DefaultData.js
   GeneralChromeScript.js
   PMIValidationChromeScript.js
   RequestShippingChromeScript.js
   ShippingOptionsChromeScript.js
   ShowPaymentChromeScript.js
@@ -20,17 +20,17 @@ support-files =
 
 [test_abortPayment.html]
 run-if = nightly_build # Bug 1390018: Depends on the Nightly-only UI service
 [test_basiccard.html]
 [test_block_none10s.html]
 skip-if = e10s # Bug 1408250: Don't expose PaymentRequest Constructor in non-e10s
 [test_canMakePayment.html]
 run-if = nightly_build # Bug 1390737: Depends on the Nightly-only UI service
-[test_cleanupPayment.html]
+[test_closePayment.html]
 [test_constructor.html]
 [test_currency_amount_validation.html]
 skip-if = (verify && debug)
 [test_payment-request-in-iframe.html]
 [test_pmi_validation.html]
 skip-if = (verify && debug)
 [test_requestShipping.html]
 [test_shippingOptions.html]
--- a/dom/payments/test/simple_payment_request.html
+++ b/dom/payments/test/simple_payment_request.html
@@ -9,34 +9,73 @@ const methods = [
 ];
 const details = {
   id: "simple details",
   total: {
     label: "Donation",
     amount: { currency: "USD", value: "55.00" },
   },
 };
+const updatedDetails = {
+  id: "simple details",
+  total: {
+    label: "Donation",
+    amount: { currency: "USD", value: "55.00" },
+  },
+  error: "",
+};
 
 let request;
+let shippingChangedEvent;
+
 let msg = "successful";
 try {
   request = new PaymentRequest(methods, details);
+  request.onshippingoptionchange = (event) => {
+    shippingChangedEvent = event;
+    window.parent.postMessage("successful", "*");
+  };
+  request.onshippingaddresschange = (event) => {
+    shippingChangedEvent = event;
+    window.parent.postMessage("successful", "*");
+  };
+
 } catch (err) {
   msg = err.name;
 }
 window.parent.postMessage(msg, "*");
 
+
 if (request) {
   window.onmessage = async ({ data: action }) => {
+    msg = "successful";
     switch (action) {
       case "show PaymentRequest":
         const responsePromise = request.show();
-        window.parent.postMessage("successful", "*");
+        window.parent.postMessage(msg, "*");
         try {
           await responsePromise;
-        } catch (err) { /* graceful abort */ }
+        } catch (err) {
+          if (err.name !== "AbortError") {
+            msg = err.name;
+          }
+        }
+        window.parent.postMessage(msg, "*")
+        break;
+      case "updateWith PaymentRequest":
+        if (shippingChangedEvent) {
+          try {
+            shippingChangedEvent.updateWith(updatedDetails);
+          } catch(err) {
+            if (err.name !== "InvalidStateError") {
+              msg = err.name;
+            }
+          }
+          window.parent.postMessage(msg, "*");
+          shippingChangedEvent = undefined;
+        }
         break;
       default:
         window.parent.postMessage(`fail - unknown postmessage action: ${action}`, "*");
     }
   };
 }
 </script>
rename from dom/payments/test/test_cleanupPayment.html
rename to dom/payments/test/test_closePayment.html
--- a/dom/payments/test/test_cleanupPayment.html
+++ b/dom/payments/test/test_closePayment.html
@@ -1,179 +1,224 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=1408234
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test for Bug 1408234</title>
+  <title>Test for closing PaymentRequest</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript">
 
   "use strict";
   SimpleTest.waitForExplicitFinish();
 
-  var gUrl = SimpleTest.getTestFileURL('CleanupChromeScript.js');
+  var gUrl = SimpleTest.getTestFileURL('ClosePaymentChromeScript.js');
   var gScript = SpecialPowers.loadChromeScript(gUrl);
   var testName = "";
 
   function testFailHandler(message) {
     ok(false, testName + ": " + message);
   }
   function testPassHandler(message) {
     ok(true, testName + ": " + message);
   }
   gScript.addMessageListener("test-fail", testFailHandler);
   gScript.addMessageListener("test-pass", testPassHandler);
-  
-  function cleanupCheck(resolveFunc) {
-    gScript.addMessageListener("cleanup-check-complete", function checkCompleteHandler() {
-      gScript.removeMessageListener("cleanup-check-complete", checkCompleteHandler);
-      resolveFunc();
+
+  async function requestChromeAction(action, params) {
+    gScript.sendAsyncMessage(action, params);
+    await new Promise(resolve => {
+      gScript.addMessageListener(`${action}-complete`, function completeListener() {
+        gScript.removeMessageListener(`${action}-complete`, completeListener);
+        resolve();
+      });
     });
-    gScript.sendAsyncMessage("cleanup-check");
   }
 
-  function paymentNumCheck(resolveFunc, numPayments) {
-    gScript.addMessageListener("payment-num-check-complete", function checkCompleteHandler() {
-      gScript.removeMessageListener("payment-num-check-complete", checkCompleteHandler);
-      resolveFunc();
-    });
-    gScript.sendAsyncMessage("payment-num-check", numPayments);
-  }
-
-  function paymentNumSet() {
-    gScript.addMessageListener("payment-num-set-complete", function setCompleteHandler() {
-      gScript.removeMessageListener("payment-num-set-complete", setCompleteHandler);
-    });
-    gScript.sendAsyncMessage("payment-num-set");
-  }
-
-  function testCleanupByReloading() {
-    paymentNumSet();
-    return new Promise((resolve, reject) => {
-      testName = "testCleanupByReloading";
+  function testCloseByReloading() {
+    return new Promise(async (resolve, reject) => {
+      testName = "testCloseByReloading";
       let expectedResults = ["successful", "successful"];
       let nextStatus = ["creating", "reloading"];
       let currStatus = nextStatus.shift();
       let ifr = document.createElement('iframe');
-      
-      let listener = function(event) {
+      await requestChromeAction("payment-num-set");
+      let listener = async function(event) {
         let expected = expectedResults.shift();
         is(event.data, expected,
           testName + ": Expected '" + expected + "' when " + currStatus +
           ", but got '" + event.data + "'");
         if (currStatus === "creating") {
           ifr.contentWindow.location.reload();
         } else if (currStatus === "reloading") {
           window.removeEventListener("message", listener);
-          paymentNumCheck(resolve, 1);
+          await requestChromeAction("payment-num-check", 1);
           document.body.removeChild(ifr);
+          resolve();
         }
         currStatus = nextStatus.shift();
       }
       window.addEventListener("message", listener);
       ifr.src = "simple_payment_request.html";
       document.body.appendChild(ifr);
     });
   }
 
-  function testCleanupByRedirecting() {
+  function testCloseByRedirecting() {
     return new Promise((resolve, reject) => {
-      testName = "testCleanupByRedirecting";
+      testName = "testCloseByRedirecting";
       let expectedResults = ["successful", "successful"];
       let nextStatus = ["creating", "redirecting"];
       let currStatus = nextStatus.shift();
       let ifr = document.createElement('iframe');
-      let listener = function(event) {
+      let listener = async function(event) {
         let expected = expectedResults.shift();
         is(event.data, expected,
           testName + ": Expected '" + expected + "' when " + currStatus +
           ", but got '" + event.data + "'");
         if (currStatus === "creating") {
           ifr.src = "blank_page.html";
         } else if (currStatus === "redirecting"){
           window.removeEventListener("message", listener);
-          cleanupCheck(resolve);
+          await requestChromeAction("close-check");
           document.body.removeChild(ifr);
+          resolve();
         }
         currStatus = nextStatus.shift();
       };
       window.addEventListener("message", listener);
       ifr.src = "simple_payment_request.html";
       document.body.appendChild(ifr);
     });
   }
 
-  function testCleanupByRedirectingAfterShow() {
+  function testCloseByRedirectingAfterShow() {
     return new Promise((resolve, reject) => {
-      testName = "testCleanupByRedirectingAfterShow";
+      testName = "testCloseByRedirectingAfterShow";
       let nextStatus = ["creating", "showing", "redirecting"];
       let currStatus = nextStatus.shift();
       let expectedResults = ["successful", "successful", "successful"];
       let ifr = document.createElement('iframe');
-      let listener = (event) => {
+      let handler = undefined;
+      let listener = async (event) => {
         let expected = expectedResults.shift();
         is(event.data, expected,
           testName + ": Expected '" + expected + "' when " + currStatus +
           ", but got '" + event.data + "'");
-
         if (currStatus === "creating") {
+          handler = SpecialPowers.getDOMWindowUtils(ifr.contentWindow).setHandlingUserInput(true);
           ifr.contentWindow.postMessage("show PaymentRequest", "*");
         } else if (currStatus === "showing") {
+          handler.destruct();
           ifr.src = "blank_page.html";
         } else if (currStatus === "redirecting") {
           window.removeEventListener("message", listener);
-          cleanupCheck(resolve);
+          await requestChromeAction("close-check");
+          await requestChromeAction("reject-payment", true);
           document.body.removeChild(ifr);
+          resolve();
         }
         currStatus = nextStatus.shift();
       }
       window.addEventListener("message", listener);
       ifr.src = "simple_payment_request.html";
       document.body.appendChild(ifr);
     });
   }
 
-  function testCleanupByRemovingIframe() {
+  function testCloseByRemovingIframe() {
     return new Promise((resolve, reject) => {
-      testName = "testCleanupByRemovingIframe";
+      testName = "testCloseByRemovingIframe";
       let expectedResults = ["successful"];
       let nextStatus = ["creating"];
       let currStatus = nextStatus.shift();
       let ifr = document.createElement('iframe');
-      let listener = function(event) {
+      let listener = async function(event) {
         let expected = expectedResults.shift();
         is(event.data, expected,
           testName + ": Expected '" + expected + "' when " + currStatus +
           ", but got '" + event.data + "'");
         document.body.removeChild(ifr);
         window.removeEventListener("message", listener);
-        cleanupCheck(resolve);
+        await requestChromeAction("close-check");
+        resolve();
       };
       window.addEventListener("message", listener);
       ifr.src = "simple_payment_request.html";
       document.body.appendChild(ifr);
     });
   }
 
+  function testUpdateWithRespondedPayment() {
+    return new Promise(resolve => {
+      testName = "testUpdateWithRespondedPayment";
+      let nextStatus = ["creating", "showing", "closing", "updating", "finishing"];
+      let currStatus = nextStatus.shift();
+      let ifr = document.createElement('iframe');
+      let handler = undefined;
+      let listener = async function(event) {
+        is(event.data, "successful",
+          testName + ": Expected 'successful' when " + currStatus +
+          ", but got '" + event.data + "'");
+        switch (currStatus) {
+          case "creating":
+            handler = SpecialPowers.getDOMWindowUtils(ifr.contentWindow).setHandlingUserInput(true);
+            ifr.contentWindow.postMessage("show PaymentRequest", "*");
+            break;
+          case "showing":
+            await requestChromeAction("update-payment");
+            break;
+          case "closing":
+            await requestChromeAction("reject-payment", false);
+            break;
+          case "updating":
+            await requestChromeAction("close-check");
+            ifr.contentWindow.postMessage("updateWith PaymentRequest", "*");
+            break;
+          case "finishing":
+            handler.destruct();
+            document.body.removeChild(ifr);
+            window.removeEventListener("message", listener);
+            resolve();
+            break;
+          default:
+            ok(false, testName + ": Unknown status()" + currStatus);
+            break;
+        }
+        currStatus = nextStatus.shift();
+      }
+      window.addEventListener("message", listener);
+      ifr.src = "simple_payment_request.html";
+      document.body.appendChild(ifr);
+    });
+  }
+
   function teardown() {
-    gScript.removeMessageListener("test-fail", testFailHandler);
-    gScript.removeMessageListener("test-pass", testPassHandler);
-    gScript.destroy();
-    SimpleTest.finish();
+    return new Promise((resolve, reject) => {
+      gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
+        gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
+        gScript.removeMessageListener("test-fail", testFailHandler);
+        gScript.removeMessageListener("test-pass", testPassHandler);
+        gScript.destroy();
+        SimpleTest.finish();
+        resolve();
+      });
+      gScript.sendAsyncMessage("teardown");
+    });
   }
 
   function runTests() {
-    testCleanupByReloading()
-    .then(testCleanupByRedirecting)
-    .then(testCleanupByRedirectingAfterShow)
-    .then(testCleanupByRemovingIframe)
+    testCloseByReloading()
+    .then(testCloseByRedirecting)
+    .then(testCloseByRedirectingAfterShow)
+    .then(testCloseByRemovingIframe)
+    .then(testUpdateWithRespondedPayment)
     .then(teardown)
     .catch( e => {
       ok(false, "Unexpected error: " + e.name);
       SimpleTest.finish();
     });
   }
 
   window.addEventListener('load', function() {
@@ -182,10 +227,11 @@ https://bugzilla.mozilla.org/show_bug.cg
         ['dom.payments.request.enabled', true],
       ]
     }, runTests);
   });
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1408234">Mozilla Bug 1408234</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1483470">Mozilla Bug 1483470</a>
 </body>
 </html>