Title: [223910] trunk
Revision
223910
Author
aes...@apple.com
Date
2017-10-24 12:53:44 -0700 (Tue, 24 Oct 2017)

Log Message

[Payment Request] Implement the "PaymentRequest updated" algorithm
https://bugs.webkit.org/show_bug.cgi?id=178689

Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

* web-platform-tests/payment-request/payment-request-update-event-updatewith-method.https-expected.txt:

Source/WebCore:

Implemented the "PaymentRequest updated" algorithm by firing shippingaddresschange and
shippingoptionchange events at the right times and implementing
PaymentRequestUpdateEvent.updateWith().

Tests: http/tests/paymentrequest/payment-request-change-shipping-address.https.html
       http/tests/paymentrequest/payment-request-change-shipping-option.https.html
       http/tests/paymentrequest/updateWith-method-pmi-handling.https.html

* Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp:
(WebCore::convertAndValidate): Added. Converts a PaymentDetailsInit to a
ApplePaySessionPaymentRequest::TotalAndLineItems.
(WebCore::ApplePayPaymentHandler::shippingAddressUpdated): Created a ShippingContactUpdate
and passed it to PaymentCoordinator::completeShippingContactSelection().
(WebCore::ApplePayPaymentHandler::shippingOptionUpdated): Created a ShippingMethodUpdate and
passed it to PaymentCoordinator::completeShippingMethodSelection().
* Modules/applepay/paymentrequest/ApplePayPaymentHandler.h:
* Modules/paymentrequest/PaymentHandler.h:
* Modules/paymentrequest/PaymentRequest.cpp:
(WebCore::checkAndCanonicalizeDetails): Moved the logic for checking and canonicalizing a
PaymentDetailsBase from PaymentRequest::create() to here.
(WebCore::PaymentRequest::create): Called checkAndCanonicalizeDetails().
(WebCore::PaymentRequest::abortWithException): Moved the body of stop() to here and
parameterized the Exception with which to abort m_showPromise.
(WebCore::PaymentRequest::stop): Called abortWithException() with an AbortError.
(WebCore::PaymentRequest::shippingAddressChanged): Called dispatchUpdateEvent() with
shippingaddresschangeEvent.
(WebCore::PaymentRequest::shippingOptionChanged): Ditto with shippingoptionchangeEvent.
(WebCore::PaymentRequest::dispatchUpdateEvent): Created a PaymentRequestUpdateEvent and
dispatched it.
(WebCore::PaymentRequest::updateWith): Added a settle handler to m_detailsPromise.
(WebCore::PaymentRequest::settleDetailsPromise): Updated the PaymentRequest with the new
details and called PaymentHandler::shippingAddressUpdated() or
PaymentHandler::shippingOptionUpdated().
* Modules/paymentrequest/PaymentRequest.h:
* Modules/paymentrequest/PaymentRequestUpdateEvent.cpp:
(WebCore::PaymentRequestUpdateEvent::PaymentRequestUpdateEvent):
(WebCore::PaymentRequestUpdateEvent::updateWith): Called PaymentRequest::updateWith().
(WebCore::PaymentRequestUpdateEvent::eventInterface const): Returned
PaymentRequestUpdateEventInterfaceType.
* Modules/paymentrequest/PaymentRequestUpdateEvent.h:
* Modules/paymentrequest/PaymentRequestUpdateEvent.idl:
* testing/MockPaymentCoordinator.cpp:
(WebCore::MockPaymentCoordinator::canMakePaymentsWithActiveCard):
(WebCore::MockPaymentCoordinator::openPaymentSetup):
(WebCore::MockPaymentCoordinator::completeMerchantValidation): Stopped calling
PaymentCoordinator::didAuthorizePayment().
(WebCore::MockPaymentCoordinator::changeShippingOption): Called
PaymentCoordinator::didSelectShippingMethod().
(WebCore::MockPaymentCoordinator::acceptPayment): Called
PaymentCoordinator::didAuthorizePayment().
* testing/MockPaymentCoordinator.h:
* testing/MockPaymentCoordinator.idl:

LayoutTests:

* http/tests/paymentrequest/payment-request-change-shipping-address.https-expected.txt: Added.
* http/tests/paymentrequest/payment-request-change-shipping-address.https.html: Copied from imported/w3c/web-platform-tests/payment-request/shipping-address-changed-manual.https.html.
* http/tests/paymentrequest/payment-request-change-shipping-option.https-expected.txt: Added.
* http/tests/paymentrequest/payment-request-change-shipping-option.https.html: Copied from imported/w3c/web-platform-tests/payment-request/change-shipping-option-manual.https.html.
* http/tests/paymentrequest/resources/helpers.js:
(async.getPaymentRequestResponse):
* http/tests/paymentrequest/updateWith-method-pmi-handling.https-expected.txt: Added.
* http/tests/paymentrequest/updateWith-method-pmi-handling.https.html: Copied from imported/w3c/web-platform-tests/payment-request/updateWith-method-pmi-handling-manual.https.html.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (223909 => 223910)


--- trunk/LayoutTests/ChangeLog	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/LayoutTests/ChangeLog	2017-10-24 19:53:44 UTC (rev 223910)
@@ -1,3 +1,19 @@
+2017-10-24  Andy Estes  <aes...@apple.com>
+
+        [Payment Request] Implement the "PaymentRequest updated" algorithm
+        https://bugs.webkit.org/show_bug.cgi?id=178689
+
+        Reviewed by Alex Christensen.
+
+        * http/tests/paymentrequest/payment-request-change-shipping-address.https-expected.txt: Added.
+        * http/tests/paymentrequest/payment-request-change-shipping-address.https.html: Copied from imported/w3c/web-platform-tests/payment-request/shipping-address-changed-manual.https.html.
+        * http/tests/paymentrequest/payment-request-change-shipping-option.https-expected.txt: Added.
+        * http/tests/paymentrequest/payment-request-change-shipping-option.https.html: Copied from imported/w3c/web-platform-tests/payment-request/change-shipping-option-manual.https.html.
+        * http/tests/paymentrequest/resources/helpers.js:
+        (async.getPaymentRequestResponse):
+        * http/tests/paymentrequest/updateWith-method-pmi-handling.https-expected.txt: Added.
+        * http/tests/paymentrequest/updateWith-method-pmi-handling.https.html: Copied from imported/w3c/web-platform-tests/payment-request/updateWith-method-pmi-handling-manual.https.html.
+
 2017-10-24  David Kilzer  <ddkil...@apple.com>
 
         [Regression] Webkit "-apple-system" font fallback token handles font weights of PingFang incorrectly.

Added: trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-address.https-expected.txt (0 => 223910)


--- trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-address.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-address.https-expected.txt	2017-10-24 19:53:44 UTC (rev 223910)
@@ -0,0 +1,3 @@
+
+PASS Test for PaymentRequest shippingAddress attribute 
+

Added: trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-address.https.html (0 => 223910)


--- trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-address.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-address.https.html	2017-10-24 19:53:44 UTC (rev 223910)
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<!--  Copyright © 2017 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang).  -->
+<meta charset="utf-8">
+<title>Test for PaymentRequest shippingAddress attribute</title>
+<link rel="help" href=""
+<link rel="help" href=""
+<script src=""
+<script src=""
+<script>
+setup({ explicit_done: true, explicit_timeout: true });
+const applePay = Object.freeze({
+    supportedMethods: "https://apple.com/apple-pay",
+    data: {
+        version: 2,
+        merchantIdentifier: '',
+        merchantCapabilities: ['supports3DS'],
+        supportedNetworks: ['visa', 'masterCard'],
+        countryCode: 'US',
+    },
+});
+const validMethods = Object.freeze([applePay]);
+const validAmount = Object.freeze({ currency: "USD", value: "5.00" });
+const validTotal = Object.freeze({
+  label: "label",
+  amount: validAmount,
+});
+const validShippingOption = Object.freeze({
+  id: "valid",
+  label: "Shipping Option",
+  amount: validAmount,
+  selected: false,
+});
+const validDetails = Object.freeze({
+  total: validTotal,
+  shippingOptions: [validShippingOption],
+});
+const requestShipping = Object.freeze({
+  requestShipping: true,
+});
+
+function testShippingAddressChange() {
+  const shippingAddress = {
+      countryCode: 'US',
+      addressLines: [''],
+      administrativeArea: '',
+      locality: '',
+      subLocality: '',
+      postalCode: '',
+      localizedName: '',
+      phoneNumber: '',
+      emailAddress: '',
+  };
+  internals.mockPaymentCoordinator.setShippingAddress(shippingAddress);
+  promise_test(async t => {
+    const request = new PaymentRequest(
+      validMethods,
+      validDetails,
+      requestShipping
+    );
+    assert_equals(
+      request.shippingAddress,
+      null,
+      "request.shippingAddress must initially be null"
+    );
+    request._onapplepayvalidatemerchant_ = event => {
+        event.complete({ });
+    };
+    const listenerPromise = new Promise(resolve => {
+      request.addEventListener("shippingaddresschange", () => {
+        resolve(request.shippingAddress);
+      });
+    });
+    const handlerPromise = new Promise(resolve => {
+      request._onshippingaddresschange_ = () => {
+        resolve(request.shippingAddress);
+      };
+    });
+    request.show().catch(err => err);
+    const results = await Promise.all([listenerPromise, handlerPromise]);
+    assert_true(
+      results.every(obj => obj instanceof PaymentAddress),
+      "Expected instances of PaymentAddress"
+    );
+    await request.abort();
+  });
+  done();
+}
+testShippingAddressChange();
+</script>
+

Added: trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-option.https-expected.txt (0 => 223910)


--- trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-option.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-option.https-expected.txt	2017-10-24 19:53:44 UTC (rev 223910)
@@ -0,0 +1,3 @@
+
+PASS Test for PaymentRequest shippingOption attribute 
+

Added: trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-option.https.html (0 => 223910)


--- trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-option.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/paymentrequest/payment-request-change-shipping-option.https.html	2017-10-24 19:53:44 UTC (rev 223910)
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<!--  Copyright © 2017 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang).  -->
+<!--  Copyright (C) 2017 Apple Inc. All rights reserved.  -->
+<!-- FIXME: Upstream this test to web-platform-tests/payment-request/. -->
+<meta charset="utf-8">
+<title>Test for PaymentRequest shippingOption attribute</title>
+<link rel="help" href=""
+<link rel="help" href=""
+<script src=""
+<script src=""
+<script>
+setup({ explicit_done: true, explicit_timeout: true });
+const applePay = Object.freeze({
+    supportedMethods: "https://apple.com/apple-pay",
+    data: {
+        version: 2,
+        merchantIdentifier: '',
+        merchantCapabilities: ['supports3DS'],
+        supportedNetworks: ['visa', 'masterCard'],
+        countryCode: 'US',
+    },
+});
+const validMethods = Object.freeze([applePay]);
+const validAmount = Object.freeze({ currency: "USD", value: "5.00" });
+const validTotal = Object.freeze({
+  label: "label",
+  amount: validAmount,
+});
+const validDetails = Object.freeze({ total: validTotal });
+
+const validShippingOption1 = Object.freeze({
+  id: "valid-1",
+  label: "PICK ME!",
+  amount: validAmount,
+  selected: false,
+});
+
+const validShippingOption2 = Object.freeze({
+  id: "initially-selected",
+  label: "Valid shipping option 2",
+  amount: validAmount,
+  selected: true,
+});
+
+const requestShipping = Object.freeze({
+  requestShipping: true,
+});
+
+function testShippingOptionChanged() {
+  promise_test(async t => {
+    const detailsWithShippingOptions = Object.assign({}, validDetails, {
+      shippingOptions: [validShippingOption1, validShippingOption2],
+    });
+    const request = new PaymentRequest(
+      validMethods,
+      detailsWithShippingOptions,
+      requestShipping
+    );
+    request._onapplepayvalidatemerchant_ = event => {
+        event.complete({ });
+        internals.mockPaymentCoordinator.changeShippingOption("valid-1");
+    };
+    assert_equals(
+      request.shippingOption,
+      "initially-selected",
+      "Must be 'initially-selected', as the selected member is true"
+    );
+    const listenerPromise = new Promise(resolve => {
+      request.addEventListener("shippingoptionchange", () => {
+        resolve(request.shippingOption);
+      });
+    });
+    const handlerPromise = new Promise(resolve => {
+      request._onshippingoptionchange_ = () => {
+        resolve(request.shippingOption);
+      };
+    });
+    request.show().catch(err => err);
+
+    const results = await Promise.all([listenerPromise, handlerPromise]);
+    assert_true(
+      results.every(result => result === "valid-1"),
+      "Expected valid-1 as the shippingOption"
+    );
+    await request.abort();
+  });
+  done();
+}
+testShippingOptionChanged();
+</script>

Modified: trunk/LayoutTests/http/tests/paymentrequest/resources/helpers.js (223909 => 223910)


--- trunk/LayoutTests/http/tests/paymentrequest/resources/helpers.js	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/LayoutTests/http/tests/paymentrequest/resources/helpers.js	2017-10-24 19:53:44 UTC (rev 223910)
@@ -94,7 +94,10 @@
   const request = new PaymentRequest(methods, details, options);
   request._onshippingaddresschange_ = ev => ev.updateWith(details);
   request._onshippingoptionchange_ = ev => ev.updateWith(details);
-  request._onapplepayvalidatemerchant_ = ev => ev.complete({});
+  request._onapplepayvalidatemerchant_ = ev => {
+      ev.complete({});
+      internals.mockPaymentCoordinator.acceptPayment();
+  };
   const response = await request.show();
   return { request, response };
 }

Added: trunk/LayoutTests/http/tests/paymentrequest/updateWith-method-pmi-handling.https-expected.txt (0 => 223910)


--- trunk/LayoutTests/http/tests/paymentrequest/updateWith-method-pmi-handling.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/paymentrequest/updateWith-method-pmi-handling.https-expected.txt	2017-10-24 19:53:44 UTC (rev 223910)
@@ -0,0 +1,21 @@
+Must throw if the URL has a password.
+Must throw if the URL has a username.
+Must throw if the URL has a username and a password.
+Must throw if it's http, and has a username and password.
+Must throw if the URL is invalid (port range).
+Must throw if the PMI contains characters that are out of range.
+Must throw if not https.
+Must throw if the standardized PMI contains characters outside the ascii range.
+Must throw if standardized PMI has uppercase characters.
+
+PASS smoke test 
+PASS Must throw if the URL has a password. 
+PASS Must throw if the URL has a username. 
+PASS Must throw if the URL has a username and a password. 
+PASS Must throw if it's http, and has a username and password. 
+PASS Must throw if the URL is invalid (port range). 
+PASS Must throw if the PMI contains characters that are out of range. 
+PASS Must throw if not https. 
+PASS Must throw if the standardized PMI contains characters outside the ascii range. 
+PASS Must throw if standardized PMI has uppercase characters. 
+

Added: trunk/LayoutTests/http/tests/paymentrequest/updateWith-method-pmi-handling.https.html (0 => 223910)


--- trunk/LayoutTests/http/tests/paymentrequest/updateWith-method-pmi-handling.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/paymentrequest/updateWith-method-pmi-handling.https.html	2017-10-24 19:53:44 UTC (rev 223910)
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<!--  Copyright © 2017 Mozilla and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang).  -->
+<meta charset="utf-8">
+<title>Test for validity of payment method identifiers when calling updateWith() method</title>
+<link rel="help" href=""
+<script src=""
+<script src=""
+<script>
+"use strict";
+setup({ explicit_done: true, explicit_timeout: true });
+const validMethod = Object.freeze({
+  supportedMethods: "https://:@wpt.fyi:443/payment-request",
+});
+
+const validMethods = Object.freeze([validMethod]);
+
+const validAmount = Object.freeze({
+  currency: "USD",
+  value: "1.0",
+});
+
+const validTotal = Object.freeze({
+  label: "Default Total",
+  amount: validAmount,
+});
+
+const validShippingOption = Object.freeze({
+  id: "standard",
+  label: "Shipping option",
+  amount: validAmount,
+  selected: true,
+});
+
+const validDetails = Object.freeze({
+  total: validTotal,
+  shippingOptions: [validShippingOption],
+});
+
+const validModifier = Object.freeze({
+  supportedMethods: "basic-card",
+  total: validTotal,
+});
+
+test(() => {
+  try {
+    new PaymentRequest(validMethods, validDetails);
+  } catch (err) {
+    done();
+    throw err;
+  }
+}, "smoke test");
+
+function runTest(button, { invalidMethod }) {
+  button.disabled = true;
+  const applePay = Object.freeze({
+      supportedMethods: "https://apple.com/apple-pay",
+      data: {
+          version: 2,
+          merchantIdentifier: '',
+          merchantCapabilities: ['supports3DS'],
+          supportedNetworks: ['visa', 'masterCard'],
+          countryCode: 'US',
+      },
+  });
+  promise_test(async t => {
+    const request = new PaymentRequest(
+      [applePay],
+      validDetails,
+      { requestShipping: true }
+    );
+    request._onapplepayvalidatemerchant_ = event => {
+        event.complete({ });
+    };
+    const listener = ev => {
+      const invalidModifier = Object.assign({}, validModifier, {
+        supportedMethods: invalidMethod,
+      });
+      const invalidDetails = Object.assign({}, validDetails, {
+        modifiers: [validModifier, invalidModifier],
+      });
+      ev.updateWith(invalidDetails);
+    };
+    // We test against a valid and an invalid modifier
+    request._onshippingaddresschange_ = listener;
+    // request.addEventListener("shippingaddresschange", listener, { once: true });
+    const showPromise = request.show();
+    await promise_rejects(t, new RangeError(), showPromise);
+  }, button.textContent.trim());
+}
+</script>
+<ol>
+  <li>
+    <button id="button1">
+      Must throw if the URL has a password.
+    </button>
+  </li>
+  <li>
+    <button id="button2">
+      Must throw if the URL has a username.
+    </button>
+  </li>
+  <li>
+    <button id="button3">
+      Must throw if the URL has a username and a password.
+    </button>
+  </li>
+  <li>
+    <button id="button4">
+      Must throw if it's http, and has a username and password.
+    </button>
+  </li>
+  <li>
+    <button id="button5">
+      Must throw if the URL is invalid (port range).
+    </button>
+  </li>
+  <li>
+    <button id="button6">
+      Must throw if the PMI contains characters that are out of range.
+    </button>
+  </li>
+  <li>
+    <button id="button7">
+      Must throw if not https.
+    </button>
+  </li>
+  <li>
+    <button id="button8">
+      Must throw if the standardized PMI contains characters outside the ascii range.
+    </button>
+  </li>
+  <li>
+    <button id="button9">
+      Must throw if standardized PMI has uppercase characters.
+    </button>
+  </li>
+</ol>
+<script>
+    async function runTests()
+    {
+        await runTest(document.getElementById("button1"), {invalidMethod: 'https://:passw...@example.com'});
+        await runTest(document.getElementById("button2"), {invalidMethod: 'https://usern...@example.com'});
+        await runTest(document.getElementById("button3"), {invalidMethod: 'https://username:passw...@example.com/pay'});
+        await runTest(document.getElementById("button4"), {invalidMethod: 'http://username:passw...@example.com/pay'});
+        await runTest(document.getElementById("button5"), {invalidMethod: 'http://foo.com:100000000/pay'});
+        await runTest(document.getElementById("button6"), {invalidMethod: 'basic-💳'});
+        await runTest(document.getElementById("button7"), {invalidMethod: 'not-https://wpt.fyi/payment-request'});
+        await runTest(document.getElementById("button8"), {invalidMethod: '¡basic-*-card!'});
+        await runTest(document.getElementById("button9"), {invalidMethod: 'Basic-Card'});
+        done();
+    }
+    runTests();
+</script>

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (223909 => 223910)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2017-10-24 19:53:44 UTC (rev 223910)
@@ -1,3 +1,12 @@
+2017-10-24  Andy Estes  <aes...@apple.com>
+
+        [Payment Request] Implement the "PaymentRequest updated" algorithm
+        https://bugs.webkit.org/show_bug.cgi?id=178689
+
+        Reviewed by Alex Christensen.
+
+        * web-platform-tests/payment-request/payment-request-update-event-updatewith-method.https-expected.txt:
+
 2017-10-22  Dean Jackson  <d...@apple.com>
 
         Implement drawImage(ImageBitmap) on 2d canvas

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/payment-request/payment-request-update-event-updatewith-method.https-expected.txt (223909 => 223910)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/payment-request/payment-request-update-event-updatewith-method.https-expected.txt	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/payment-request/payment-request-update-event-updatewith-method.https-expected.txt	2017-10-24 19:53:44 UTC (rev 223910)
@@ -1,9 +1,5 @@
 
 PASS Let target be the request which is dispatching the event. 
-FAIL Calling .updateWith() with an undispatched untrusted event throws "InvalidStateError" assert_throws: untrusted event of type "just a test" must throw "InvalidStateError" function "() => {
-        ev.updateWith(Promise.resolve());
-      }" threw object "TypeError: ev.updateWith is not a function. (In 'ev.updateWith(Promise.resolve())', 'ev.updateWith' is undefined)" that is not a DOMException InvalidStateError: property "code" is equal to undefined, expected 11
-FAIL Calling .updateWith() with a dispatched, untrusted event, throws "InvalidStateError" assert_throws: untrusted event of type "just a test" must throw "InvalidStateError" function "() => {
-        ev.updateWith(Promise.resolve())
-      }" threw object "TypeError: ev.updateWith is not a function. (In 'ev.updateWith(Promise.resolve())', 'ev.updateWith' is undefined)" that is not a DOMException InvalidStateError: property "code" is equal to undefined, expected 11
+PASS Calling .updateWith() with an undispatched untrusted event throws "InvalidStateError" 
+PASS Calling .updateWith() with a dispatched, untrusted event, throws "InvalidStateError" 
 

Modified: trunk/Source/WebCore/ChangeLog (223909 => 223910)


--- trunk/Source/WebCore/ChangeLog	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/ChangeLog	2017-10-24 19:53:44 UTC (rev 223910)
@@ -1,3 +1,63 @@
+2017-10-24  Andy Estes  <aes...@apple.com>
+
+        [Payment Request] Implement the "PaymentRequest updated" algorithm
+        https://bugs.webkit.org/show_bug.cgi?id=178689
+
+        Reviewed by Alex Christensen.
+
+        Implemented the "PaymentRequest updated" algorithm by firing shippingaddresschange and
+        shippingoptionchange events at the right times and implementing
+        PaymentRequestUpdateEvent.updateWith().
+
+        Tests: http/tests/paymentrequest/payment-request-change-shipping-address.https.html
+               http/tests/paymentrequest/payment-request-change-shipping-option.https.html
+               http/tests/paymentrequest/updateWith-method-pmi-handling.https.html
+
+        * Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp:
+        (WebCore::convertAndValidate): Added. Converts a PaymentDetailsInit to a
+        ApplePaySessionPaymentRequest::TotalAndLineItems.
+        (WebCore::ApplePayPaymentHandler::shippingAddressUpdated): Created a ShippingContactUpdate
+        and passed it to PaymentCoordinator::completeShippingContactSelection().
+        (WebCore::ApplePayPaymentHandler::shippingOptionUpdated): Created a ShippingMethodUpdate and
+        passed it to PaymentCoordinator::completeShippingMethodSelection().
+        * Modules/applepay/paymentrequest/ApplePayPaymentHandler.h:
+        * Modules/paymentrequest/PaymentHandler.h:
+        * Modules/paymentrequest/PaymentRequest.cpp:
+        (WebCore::checkAndCanonicalizeDetails): Moved the logic for checking and canonicalizing a
+        PaymentDetailsBase from PaymentRequest::create() to here.
+        (WebCore::PaymentRequest::create): Called checkAndCanonicalizeDetails().
+        (WebCore::PaymentRequest::abortWithException): Moved the body of stop() to here and
+        parameterized the Exception with which to abort m_showPromise.
+        (WebCore::PaymentRequest::stop): Called abortWithException() with an AbortError.
+        (WebCore::PaymentRequest::shippingAddressChanged): Called dispatchUpdateEvent() with
+        shippingaddresschangeEvent.
+        (WebCore::PaymentRequest::shippingOptionChanged): Ditto with shippingoptionchangeEvent.
+        (WebCore::PaymentRequest::dispatchUpdateEvent): Created a PaymentRequestUpdateEvent and
+        dispatched it.
+        (WebCore::PaymentRequest::updateWith): Added a settle handler to m_detailsPromise.
+        (WebCore::PaymentRequest::settleDetailsPromise): Updated the PaymentRequest with the new
+        details and called PaymentHandler::shippingAddressUpdated() or
+        PaymentHandler::shippingOptionUpdated().
+        * Modules/paymentrequest/PaymentRequest.h:
+        * Modules/paymentrequest/PaymentRequestUpdateEvent.cpp:
+        (WebCore::PaymentRequestUpdateEvent::PaymentRequestUpdateEvent):
+        (WebCore::PaymentRequestUpdateEvent::updateWith): Called PaymentRequest::updateWith().
+        (WebCore::PaymentRequestUpdateEvent::eventInterface const): Returned
+        PaymentRequestUpdateEventInterfaceType.
+        * Modules/paymentrequest/PaymentRequestUpdateEvent.h:
+        * Modules/paymentrequest/PaymentRequestUpdateEvent.idl:
+        * testing/MockPaymentCoordinator.cpp:
+        (WebCore::MockPaymentCoordinator::canMakePaymentsWithActiveCard):
+        (WebCore::MockPaymentCoordinator::openPaymentSetup):
+        (WebCore::MockPaymentCoordinator::completeMerchantValidation): Stopped calling
+        PaymentCoordinator::didAuthorizePayment().
+        (WebCore::MockPaymentCoordinator::changeShippingOption): Called
+        PaymentCoordinator::didSelectShippingMethod().
+        (WebCore::MockPaymentCoordinator::acceptPayment): Called
+        PaymentCoordinator::didAuthorizePayment().
+        * testing/MockPaymentCoordinator.h:
+        * testing/MockPaymentCoordinator.idl:
+
 2017-10-24  Alex Christensen  <achristen...@webkit.org>
 
         Apply custom header fields from WebsitePolicies to same-domain requests

Modified: trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp (223909 => 223910)


--- trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp	2017-10-24 19:53:44 UTC (rev 223910)
@@ -253,6 +253,53 @@
     paymentCoordinator().canMakePaymentsWithActiveCard(m_applePayRequest->merchantIdentifier, document().domain(), WTFMove(completionHandler));
 }
 
+static ExceptionOr<ApplePaySessionPaymentRequest::TotalAndLineItems> convertAndValidate(const PaymentDetailsInit& details)
+{
+    String currency = details.total.amount.currency;
+    auto total = convertAndValidate(details.total, currency);
+    if (total.hasException())
+        return total.releaseException();
+
+    auto lineItems = convertAndValidate(details.displayItems, currency);
+    if (lineItems.hasException())
+        return lineItems.releaseException();
+
+    return ApplePaySessionPaymentRequest::TotalAndLineItems { total.releaseReturnValue(), lineItems.releaseReturnValue() };
+}
+
+ExceptionOr<void> ApplePayPaymentHandler::shippingAddressUpdated(const String& error)
+{
+    ShippingContactUpdate update;
+
+    if (m_paymentRequest->paymentOptions().requestShipping && m_paymentRequest->paymentDetails().shippingOptions.isEmpty()) {
+        PaymentError paymentError;
+        paymentError.code = PaymentError::Code::ShippingContactInvalid;
+        paymentError.message = error;
+        update.errors.append(WTFMove(paymentError));
+    }
+
+    auto newTotalAndLineItems = convertAndValidate(m_paymentRequest->paymentDetails());
+    if (newTotalAndLineItems.hasException())
+        return newTotalAndLineItems.releaseException();
+    update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
+
+    paymentCoordinator().completeShippingContactSelection(WTFMove(update));
+    return { };
+}
+
+ExceptionOr<void> ApplePayPaymentHandler::shippingOptionUpdated()
+{
+    ShippingMethodUpdate update;
+
+    auto newTotalAndLineItems = convertAndValidate(m_paymentRequest->paymentDetails());
+    if (newTotalAndLineItems.hasException())
+        return newTotalAndLineItems.releaseException();
+    update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
+
+    paymentCoordinator().completeShippingMethodSelection(WTFMove(update));
+    return { };
+}
+
 void ApplePayPaymentHandler::complete(std::optional<PaymentComplete>&& result)
 {
     if (!result) {

Modified: trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.h (223909 => 223910)


--- trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.h	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.h	2017-10-24 19:53:44 UTC (rev 223910)
@@ -56,6 +56,8 @@
     ExceptionOr<void> show() final;
     void hide() final;
     void canMakePayment(WTF::Function<void(bool)>&& completionHandler) final;
+    ExceptionOr<void> shippingAddressUpdated(const String& error) final;
+    ExceptionOr<void> shippingOptionUpdated() final;
     void complete(std::optional<PaymentComplete>&&) final;
 
     // PaymentSession

Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.h (223909 => 223910)


--- trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.h	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.h	2017-10-24 19:53:44 UTC (rev 223910)
@@ -48,6 +48,8 @@
     virtual ExceptionOr<void> show() = 0;
     virtual void hide() = 0;
     virtual void canMakePayment(WTF::Function<void(bool)>&& completionHandler) = 0;
+    virtual ExceptionOr<void> shippingAddressUpdated(const String& error) = 0;
+    virtual ExceptionOr<void> shippingOptionUpdated() = 0;
     virtual void complete(std::optional<PaymentComplete>&&) = 0;
 };
 

Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp (223909 => 223910)


--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp	2017-10-24 19:53:44 UTC (rev 223910)
@@ -30,6 +30,9 @@
 
 #include "ApplePayPaymentHandler.h"
 #include "Document.h"
+#include "EventNames.h"
+#include "JSDOMPromise.h"
+#include "JSPaymentDetailsUpdate.h"
 #include "JSPaymentResponse.h"
 #include "PaymentAddress.h"
 #include "PaymentCurrencyAmount.h"
@@ -37,6 +40,7 @@
 #include "PaymentHandler.h"
 #include "PaymentMethodData.h"
 #include "PaymentOptions.h"
+#include "PaymentRequestUpdateEvent.h"
 #include "PaymentResponse.h"
 #include "ScriptController.h"
 #include <_javascript_Core/JSONObject.h>
@@ -43,6 +47,7 @@
 #include <_javascript_Core/ThrowScope.h>
 #include <wtf/ASCIICType.h>
 #include <wtf/RunLoop.h>
+#include <wtf/Scope.h>
 #include <wtf/UUID.h>
 
 namespace WebCore {
@@ -240,39 +245,13 @@
     return std::nullopt;
 }
 
-// Implements the PaymentRequest Constructor
-// https://www.w3.org/TR/payment-request/#constructor
-ExceptionOr<Ref<PaymentRequest>> PaymentRequest::create(Document& document, Vector<PaymentMethodData>&& methodData, PaymentDetailsInit&& details, PaymentOptions&& options)
+enum class ShouldValidatePaymentMethodIdentifier {
+    No,
+    Yes,
+};
+
+static ExceptionOr<std::tuple<String, Vector<String>>> checkAndCanonicalizeDetails(JSC::ExecState& execState, PaymentDetailsBase& details, bool requestShipping, ShouldValidatePaymentMethodIdentifier shouldValidatePaymentMethodIdentifier)
 {
-    // FIXME: Check if this document is allowed to access the PaymentRequest API based on the allowpaymentrequest attribute.
-
-    if (details.id.isNull())
-        details.id = createCanonicalUUIDString();
-
-    if (methodData.isEmpty())
-        return Exception { TypeError, ASCIILiteral("At least one payment method is required.") };
-
-    Vector<Method> serializedMethodData;
-    serializedMethodData.reserveInitialCapacity(methodData.size());
-    for (auto& paymentMethod : methodData) {
-        auto identifier = convertAndValidatePaymentMethodIdentifier(paymentMethod.supportedMethods);
-        if (!identifier)
-            return Exception { RangeError, makeString("\"", paymentMethod.supportedMethods, "\" is an invalid payment method identifier.") };
-
-        String serializedData;
-        if (paymentMethod.data) {
-            auto scope = DECLARE_THROW_SCOPE(document.execState()->vm());
-            serializedData = JSONStringify(document.execState(), paymentMethod.data.get(), 0);
-            if (scope.exception())
-                return Exception { ExistingExceptionError };
-        }
-        serializedMethodData.uncheckedAppend({ WTFMove(*identifier), WTFMove(serializedData) });
-    }
-
-    auto exception = checkAndCanonicalizeTotal(details.total.amount);
-    if (exception.hasException())
-        return exception.releaseException();
-
     for (auto& item : details.displayItems) {
         auto exception = checkAndCanonicalizeAmount(item.amount);
         if (exception.hasException())
@@ -280,7 +259,7 @@
     }
 
     String selectedShippingOption;
-    if (options.requestShipping) {
+    if (requestShipping) {
         HashSet<String> seenShippingOptionIDs;
         for (auto& shippingOption : details.shippingOptions) {
             auto exception = checkAndCanonicalizeAmount(shippingOption.amount);
@@ -299,6 +278,12 @@
     Vector<String> serializedModifierData;
     serializedModifierData.reserveInitialCapacity(details.modifiers.size());
     for (auto& modifier : details.modifiers) {
+        if (shouldValidatePaymentMethodIdentifier == ShouldValidatePaymentMethodIdentifier::Yes) {
+            auto paymentMethodIdentifier = convertAndValidatePaymentMethodIdentifier(modifier.supportedMethods);
+            if (!paymentMethodIdentifier)
+                return Exception { RangeError, makeString("\"", modifier.supportedMethods, "\" is an invalid payment method identifier.") };
+        }
+
         if (modifier.total) {
             auto exception = checkAndCanonicalizeTotal(modifier.total->amount);
             if (exception.hasException())
@@ -313,17 +298,59 @@
 
         String serializedData;
         if (modifier.data) {
-            auto scope = DECLARE_THROW_SCOPE(document.execState()->vm());
-            serializedData = JSONStringify(document.execState(), modifier.data.get(), 0);
+            auto scope = DECLARE_THROW_SCOPE(execState.vm());
+            serializedData = JSONStringify(&execState, modifier.data.get(), 0);
             if (scope.exception())
                 return Exception { ExistingExceptionError };
+            modifier.data.clear();
         }
         serializedModifierData.uncheckedAppend(WTFMove(serializedData));
     }
 
-    return adoptRef(*new PaymentRequest(document, WTFMove(options), WTFMove(details), WTFMove(serializedModifierData), WTFMove(serializedMethodData), WTFMove(selectedShippingOption)));
+    return std::make_tuple(WTFMove(selectedShippingOption), WTFMove(serializedModifierData));
 }
 
+// Implements the PaymentRequest Constructor
+// https://www.w3.org/TR/payment-request/#constructor
+ExceptionOr<Ref<PaymentRequest>> PaymentRequest::create(Document& document, Vector<PaymentMethodData>&& methodData, PaymentDetailsInit&& details, PaymentOptions&& options)
+{
+    // FIXME: Check if this document is allowed to access the PaymentRequest API based on the allowpaymentrequest attribute.
+
+    if (details.id.isNull())
+        details.id = createCanonicalUUIDString();
+
+    if (methodData.isEmpty())
+        return Exception { TypeError, ASCIILiteral("At least one payment method is required.") };
+
+    Vector<Method> serializedMethodData;
+    serializedMethodData.reserveInitialCapacity(methodData.size());
+    for (auto& paymentMethod : methodData) {
+        auto identifier = convertAndValidatePaymentMethodIdentifier(paymentMethod.supportedMethods);
+        if (!identifier)
+            return Exception { RangeError, makeString("\"", paymentMethod.supportedMethods, "\" is an invalid payment method identifier.") };
+
+        String serializedData;
+        if (paymentMethod.data) {
+            auto scope = DECLARE_THROW_SCOPE(document.execState()->vm());
+            serializedData = JSONStringify(document.execState(), paymentMethod.data.get(), 0);
+            if (scope.exception())
+                return Exception { ExistingExceptionError };
+        }
+        serializedMethodData.uncheckedAppend({ WTFMove(*identifier), WTFMove(serializedData) });
+    }
+
+    auto totalResult = checkAndCanonicalizeTotal(details.total.amount);
+    if (totalResult.hasException())
+        return totalResult.releaseException();
+
+    auto detailsResult = checkAndCanonicalizeDetails(*document.execState(), details, options.requestShipping, ShouldValidatePaymentMethodIdentifier::No);
+    if (detailsResult.hasException())
+        return detailsResult.releaseException();
+
+    auto shippingOptionAndModifierData = detailsResult.releaseReturnValue();
+    return adoptRef(*new PaymentRequest(document, WTFMove(options), WTFMove(details), WTFMove(std::get<1>(shippingOptionAndModifierData)), WTFMove(serializedMethodData), WTFMove(std::get<0>(shippingOptionAndModifierData))));
+}
+
 PaymentRequest::PaymentRequest(Document& document, PaymentOptions&& options, PaymentDetailsInit&& details, Vector<String>&& serializedModifierData, Vector<Method>&& serializedMethodData, String&& selectedShippingOption)
     : ActiveDOMObject { &document }
     , m_options { WTFMove(options) }
@@ -408,7 +435,7 @@
     setPendingActivity(this); // unsetPendingActivity() is called below in stop()
 }
 
-void PaymentRequest::stop()
+void PaymentRequest::abortWithException(Exception&& exception)
 {
     if (m_state != State::Interactive)
         return;
@@ -420,9 +447,14 @@
 
     ASSERT(m_state == State::Interactive);
     m_state = State::Closed;
-    m_showPromise->reject(Exception { AbortError });
+    m_showPromise->reject(WTFMove(exception));
 }
 
+void PaymentRequest::stop()
+{
+    abortWithException(Exception { AbortError });
+}
+
 // https://www.w3.org/TR/payment-request/#abort()-method
 ExceptionOr<void> PaymentRequest::abort(AbortPromise&& promise)
 {
@@ -492,7 +524,7 @@
 {
     ASSERT(m_state == State::Interactive);
     m_shippingAddress = WTFMove(shippingAddress);
-    // FIXME: run the PaymentRequest updated algorithm.
+    dispatchUpdateEvent(eventNames().shippingaddresschangeEvent);
 }
 
 void PaymentRequest::shippingOptionChanged(const String& shippingOption)
@@ -499,9 +531,99 @@
 {
     ASSERT(m_state == State::Interactive);
     m_shippingOption = shippingOption;
-    // FIXME: run the PaymentRequest updated algorithm.
+    dispatchUpdateEvent(eventNames().shippingoptionchangeEvent);
 }
 
+void PaymentRequest::dispatchUpdateEvent(const AtomicString& type)
+{
+    if (m_isUpdating)
+        return;
+
+    if (m_state != State::Interactive)
+        return;
+
+    auto event = PaymentRequestUpdateEvent::create(type, *this);
+    dispatchEvent(event.get());
+}
+
+ExceptionOr<void> PaymentRequest::updateWith(PaymentRequestUpdateEvent& event, Ref<DOMPromise>&& promise)
+{
+    if (!event.isTrusted())
+        return Exception { InvalidStateError };
+
+    if (event.waitForUpdate())
+        return Exception { InvalidStateError };
+
+    if (m_state != State::Interactive)
+        return Exception { InvalidStateError };
+
+    if (m_isUpdating)
+        return Exception { InvalidStateError };
+
+    event.stopPropagation();
+    event.stopImmediatePropagation();
+    event.setWaitForUpdate(true);
+    m_isUpdating = true;
+
+    m_detailsPromise = WTFMove(promise);
+    m_detailsPromise->whenSettled([this, protectedThis = makeRefPtr(this), type = event.type()]() {
+        settleDetailsPromise(type);
+    });
+
+    return { };
+}
+
+void PaymentRequest::settleDetailsPromise(const AtomicString& type)
+{
+    auto scopeExit = makeScopeExit([&] {
+        m_isUpdating = false;
+    });
+
+    if (m_detailsPromise->status() == DOMPromise::Status::Rejected) {
+        stop();
+        return;
+    }
+
+    auto& context = *m_detailsPromise->scriptExecutionContext();
+    auto throwScope = DECLARE_THROW_SCOPE(context.vm());
+    auto paymentDetailsUpdate = convertDictionary<PaymentDetailsUpdate>(*context.execState(), m_detailsPromise->result());
+    if (throwScope.exception()) {
+        abortWithException(Exception { ExistingExceptionError });
+        return;
+    }
+
+    auto totalResult = checkAndCanonicalizeTotal(paymentDetailsUpdate.total.amount);
+    if (totalResult.hasException()) {
+        abortWithException(totalResult.releaseException());
+        return;
+    }
+
+    auto detailsResult = checkAndCanonicalizeDetails(*context.execState(), paymentDetailsUpdate, m_options.requestShipping, ShouldValidatePaymentMethodIdentifier::Yes);
+    if (detailsResult.hasException()) {
+        abortWithException(detailsResult.releaseException());
+        return;
+    }
+
+    auto shippingOptionAndModifierData = detailsResult.releaseReturnValue();
+
+    m_details.total = WTFMove(paymentDetailsUpdate.total);
+    m_details.displayItems = WTFMove(paymentDetailsUpdate.displayItems);
+    if (m_options.requestShipping) {
+        m_details.shippingOptions = WTFMove(paymentDetailsUpdate.shippingOptions);
+        m_shippingOption = WTFMove(std::get<0>(shippingOptionAndModifierData));
+    }
+
+    m_details.modifiers = WTFMove(paymentDetailsUpdate.modifiers);
+    m_serializedModifierData = WTFMove(std::get<1>(shippingOptionAndModifierData));
+
+    if (type == eventNames().shippingaddresschangeEvent)
+        m_activePaymentHandler->shippingAddressUpdated(paymentDetailsUpdate.error);
+    else if (type == eventNames().shippingoptionchangeEvent)
+        m_activePaymentHandler->shippingOptionUpdated();
+    else
+        ASSERT_NOT_REACHED();
+}
+
 void PaymentRequest::accept(const String& methodName, JSC::Strong<JSC::JSObject>&& details, Ref<PaymentAddress>&& shippingAddress, const String& payerName, const String& payerEmail, const String& payerPhone)
 {
     ASSERT(m_state == State::Interactive);

Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.h (223909 => 223910)


--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.h	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.h	2017-10-24 19:53:44 UTC (rev 223910)
@@ -41,6 +41,7 @@
 class Document;
 class PaymentAddress;
 class PaymentHandler;
+class PaymentRequestUpdateEvent;
 class PaymentResponse;
 enum class PaymentComplete;
 enum class PaymentShippingType;
@@ -69,6 +70,7 @@
 
     void shippingAddressChanged(Ref<PaymentAddress>&&);
     void shippingOptionChanged(const String& shippingOption);
+    ExceptionOr<void> updateWith(PaymentRequestUpdateEvent&, Ref<DOMPromise>&&);
     void accept(const String& methodName, JSC::Strong<JSC::JSObject>&& details, Ref<PaymentAddress>&& shippingAddress, const String& payerName, const String& payerEmail, const String& payerPhone);
     void complete(std::optional<PaymentComplete>&&);
 
@@ -90,6 +92,10 @@
 
     PaymentRequest(Document&, PaymentOptions&&, PaymentDetailsInit&&, Vector<String>&& serializedModifierData, Vector<Method>&& serializedMethodData, String&& selectedShippingOption);
 
+    void dispatchUpdateEvent(const AtomicString& type);
+    void settleDetailsPromise(const AtomicString& type);
+    void abortWithException(Exception&&);
+
     // ActiveDOMObject
     const char* activeDOMObjectName() const final { return "PaymentRequest"; }
     bool canSuspendForDocumentSuspension() const final;
@@ -110,6 +116,8 @@
     State m_state { State::Created };
     std::optional<ShowPromise> m_showPromise;
     RefPtr<PaymentHandler> m_activePaymentHandler;
+    RefPtr<DOMPromise> m_detailsPromise;
+    bool m_isUpdating { false };
 };
 
 std::optional<PaymentRequest::MethodIdentifier> convertAndValidatePaymentMethodIdentifier(const String& identifier);

Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.cpp (223909 => 223910)


--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.cpp	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.cpp	2017-10-24 19:53:44 UTC (rev 223910)
@@ -28,14 +28,33 @@
 
 #if ENABLE(PAYMENT_REQUEST)
 
+#include "PaymentRequest.h"
+
 namespace WebCore {
 
+PaymentRequestUpdateEvent::PaymentRequestUpdateEvent(const AtomicString& type, PaymentRequestUpdateEventInit&& eventInit)
+    : Event { type, WTFMove(eventInit), IsTrusted::No }
+{
+}
+
+PaymentRequestUpdateEvent::PaymentRequestUpdateEvent(const AtomicString& type, PaymentRequest& paymentRequest)
+    : Event { type, false, false }
+    , m_paymentRequest { &paymentRequest }
+{
+}
+
 PaymentRequestUpdateEvent::~PaymentRequestUpdateEvent() = default;
 
-void PaymentRequestUpdateEvent::updateWith(Ref<DOMPromise>&&)
+ExceptionOr<void> PaymentRequestUpdateEvent::updateWith(Ref<DOMPromise>&& detailsPromise)
 {
+    return m_paymentRequest->updateWith(*this, WTFMove(detailsPromise));
 }
 
+EventInterface PaymentRequestUpdateEvent::eventInterface() const
+{
+    return PaymentRequestUpdateEventInterfaceType;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(PAYMENT_REQUEST)

Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.h (223909 => 223910)


--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.h	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.h	2017-10-24 19:53:44 UTC (rev 223910)
@@ -28,15 +28,35 @@
 #if ENABLE(PAYMENT_REQUEST)
 
 #include "Event.h"
+#include "PaymentRequestUpdateEventInit.h"
 
 namespace WebCore {
 
 class DOMPromise;
+class PaymentRequest;
+struct PaymentRequestUpdateEventInit;
 
 class PaymentRequestUpdateEvent final : public Event {
 public:
+    template <typename... Args> static Ref<PaymentRequestUpdateEvent> create(Args&&... args)
+    {
+        return adoptRef(*new PaymentRequestUpdateEvent(std::forward<Args>(args)...));
+    }
     ~PaymentRequestUpdateEvent();
-    void updateWith(Ref<DOMPromise>&&);
+    ExceptionOr<void> updateWith(Ref<DOMPromise>&&);
+
+    bool waitForUpdate() const { return m_waitForUpdate; }
+    void setWaitForUpdate(bool waitForUpdate) { m_waitForUpdate = waitForUpdate; }
+
+private:
+    PaymentRequestUpdateEvent(const AtomicString& type, PaymentRequestUpdateEventInit&&);
+    PaymentRequestUpdateEvent(const AtomicString& type, PaymentRequest&);
+
+    // Event
+    EventInterface eventInterface() const final;
+
+    RefPtr<PaymentRequest> m_paymentRequest;
+    bool m_waitForUpdate { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.idl (223909 => 223910)


--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.idl	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequestUpdateEvent.idl	2017-10-24 19:53:44 UTC (rev 223910)
@@ -27,7 +27,8 @@
     Conditional=PAYMENT_REQUEST,
     Constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict),
     EnabledBySetting=PaymentRequest,
+    Exposed=Window,
     SecureContext
 ] interface PaymentRequestUpdateEvent : Event {
-    void updateWith(Promise<PaymentDetailsUpdate> detailsPromise);
+    [MayThrowException] void updateWith(Promise<PaymentDetailsUpdate> detailsPromise);
 };

Modified: trunk/Source/WebCore/testing/MockPaymentCoordinator.cpp (223909 => 223910)


--- trunk/Source/WebCore/testing/MockPaymentCoordinator.cpp	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/testing/MockPaymentCoordinator.cpp	2017-10-24 19:53:44 UTC (rev 223910)
@@ -62,7 +62,7 @@
 
 void MockPaymentCoordinator::canMakePaymentsWithActiveCard(const String&, const String&, Function<void(bool)>&& completionHandler)
 {
-    RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
+    RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] {
         completionHandler(true);
     });
 }
@@ -69,7 +69,7 @@
 
 void MockPaymentCoordinator::openPaymentSetup(const String&, const String&, Function<void(bool)>&& completionHandler)
 {
-    RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
+    RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] {
         completionHandler(true);
     });
 }
@@ -101,9 +101,23 @@
     dispatchIfShowing([mainFrame = makeRef(m_mainFrame), shippingAddress = m_shippingAddress]() {
         ApplePayPaymentContact contact = shippingAddress;
         mainFrame->paymentCoordinator().didSelectShippingContact(MockPaymentContact { WTFMove(contact) });
+    });
+}
 
+void MockPaymentCoordinator::changeShippingOption(String&& shippingOption)
+{
+    dispatchIfShowing([mainFrame = makeRef(m_mainFrame), shippingOption = WTFMove(shippingOption)]() mutable {
+        ApplePaySessionPaymentRequest::ShippingMethod shippingMethod;
+        shippingMethod.identifier = WTFMove(shippingOption);
+        mainFrame->paymentCoordinator().didSelectShippingMethod(shippingMethod);
+    });
+}
+
+void MockPaymentCoordinator::acceptPayment()
+{
+    dispatchIfShowing([mainFrame = makeRef(m_mainFrame), shippingAddress = m_shippingAddress]() mutable {
         ApplePayPayment payment;
-        payment.shippingContact = shippingAddress;
+        payment.shippingContact = WTFMove(shippingAddress);
         mainFrame->paymentCoordinator().didAuthorizePayment(MockPayment { WTFMove(payment) });
     });
 }

Modified: trunk/Source/WebCore/testing/MockPaymentCoordinator.h (223909 => 223910)


--- trunk/Source/WebCore/testing/MockPaymentCoordinator.h	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/testing/MockPaymentCoordinator.h	2017-10-24 19:53:44 UTC (rev 223910)
@@ -39,6 +39,8 @@
     explicit MockPaymentCoordinator(MainFrame&);
 
     void setShippingAddress(MockPaymentAddress&& shippingAddress) { m_shippingAddress = WTFMove(shippingAddress); }
+    void changeShippingOption(String&& shippingOption);
+    void acceptPayment();
 
     void ref() const { }
     void deref() const { }

Modified: trunk/Source/WebCore/testing/MockPaymentCoordinator.idl (223909 => 223910)


--- trunk/Source/WebCore/testing/MockPaymentCoordinator.idl	2017-10-24 19:33:20 UTC (rev 223909)
+++ trunk/Source/WebCore/testing/MockPaymentCoordinator.idl	2017-10-24 19:53:44 UTC (rev 223910)
@@ -28,4 +28,6 @@
     NoInterfaceObject,
 ] interface MockPaymentCoordinator {
     void setShippingAddress(MockPaymentAddress shippingAddress);
+    void changeShippingOption(DOMString shippingOption);
+    void acceptPayment();
 };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to