[WebIDL] Remove use of Dictionary in ApplePaySession
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Dec 2016 18:47:01 +0000 (18:47 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Dec 2016 18:47:01 +0000 (18:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165787

Reviewed by Anders Carlsson.

Source/WebCore:

First take at generating the bindings for ApplePaySession and removing
all use of Dictionary.

- Removes all use of Dictionary!
- Removes use of logging errors to the console with improved Exception messages.
- Use ExceptionOr extensively to pass exception state.

Still to do:
    - Reconcile / merge ApplePaySession::PaymentRequest with WebCore::PaymentRequest
      and all the sub-objects held within.
    - Remove PaymentRequestValidator entirely, merging validation into the validation
      we already do in ApplePaySession.cpp
    - Make ApplePayEvents use generated dictionary creation code.

Test: http/tests/ssl/applepay/ApplePaySession.html

* Modules/applepay/ApplePaySession.cpp:
(WebCore::convertAndValidate):
(WebCore::canCallApplePaySessionAPIs):
(WebCore::ApplePaySession::create):
(WebCore::ApplePaySession::ApplePaySession):
(WebCore::ApplePaySession::supportsVersion):
(WebCore::ApplePaySession::canMakePayments):
(WebCore::ApplePaySession::canMakePaymentsWithActiveCard):
(WebCore::ApplePaySession::openPaymentSetup):
(WebCore::ApplePaySession::begin):
(WebCore::ApplePaySession::completeMerchantValidation):
(WebCore::ApplePaySession::completeShippingMethodSelection):
(WebCore::ApplePaySession::completeShippingContactSelection):
(WebCore::ApplePaySession::completePaymentMethodSelection):
(WebCore::ApplePaySession::didSelectShippingMethod):
(WebCore::createContactFields): Deleted.
(WebCore::toLineItemType): Deleted.
(WebCore::isValidLineItemPropertyName): Deleted.
(WebCore::createLineItem): Deleted.
(WebCore::createLineItems): Deleted.
(WebCore::createMerchantCapabilities): Deleted.
(WebCore::createSupportedNetworks): Deleted.
(WebCore::toShippingType): Deleted.
(WebCore::isValidShippingMethodPropertyName): Deleted.
(WebCore::createShippingMethod): Deleted.
(WebCore::createShippingMethods): Deleted.
(WebCore::isValidPaymentRequestPropertyName): Deleted.
(WebCore::createPaymentRequest): Deleted.
* Modules/applepay/ApplePaySession.h:
Replace hand written dictionary extraction code with autogenerated code
and hand written additional validation.

* Modules/applepay/ApplePaySession.idl:
Add helper dictionaries and enums.

* Modules/applepay/PaymentRequestValidator.cpp:
(WebCore::PaymentRequestValidator::validate):
(WebCore::PaymentRequestValidator::validateTotal):
(WebCore::validateCountryCode):
(WebCore::validateCurrencyCode):
(WebCore::validateMerchantCapabilities):
(WebCore::validateSupportedNetworks):
(WebCore::validateShippingMethod):
(WebCore::validateShippingMethods):
(WebCore::PaymentRequestValidator::PaymentRequestValidator): Deleted.
(WebCore::PaymentRequestValidator::~PaymentRequestValidator): Deleted.
(WebCore::PaymentRequestValidator::validateCountryCode): Deleted.
(WebCore::PaymentRequestValidator::validateCurrencyCode): Deleted.
(WebCore::PaymentRequestValidator::validateMerchantCapabilities): Deleted.
(WebCore::PaymentRequestValidator::validateShippingMethod): Deleted.
(WebCore::PaymentRequestValidator::validateSupportedNetworks): Deleted.
(WebCore::PaymentRequestValidator::validateShippingMethods): Deleted.
* Modules/applepay/PaymentRequestValidator.h:
Instead of reporting the validation errors to the console, pass them in the exception.
This allows us to remove the window member, and move the helpers to the implementation
file as statics.

* WebCore.xcodeproj/project.pbxproj:
Remove file.

* bindings/generic/IDLTypes.h:
(WebCore::IDLObject::nullValue):
(WebCore::IDLObject::isNullValue):
(WebCore::IDLObject::extractValueFromNullable):
Add nullability traits for IDLObject.

* bindings/js/JSApplePaySessionCustom.cpp:
Removed.

Tools:

* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::initializeWebViewConfiguration):
(WTR::TestController::platformCreateWebView):
Enable ApplePay for the tests (where supported).

LayoutTests:

* http/tests/ssl/applepay: Added.
* http/tests/ssl/applepay/ApplePaySession-expected.txt: Added.
* http/tests/ssl/applepay/ApplePaySession.html: Added.
Add a compressive test of the handling of the payment request to the ApplePaySession
constructor. For further testing, we will need to mock out bits of the underlying
coordinator, but this allows for testing the aspect I am changing. The applepay
directory is in the ssl directory, as all use of ApplePay requires https.

* TestExpectations:
* platform/ios-simulator-wk2/TestExpectations:
* platform/mac-wk2/TestExpectations:
Only enable the tests on iOS 10.10 and greater, and macOS 10.12 and greater, WebKit2.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209760 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/http/tests/ssl/applepay/ApplePaySession-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/ssl/applepay/ApplePaySession.html [new file with mode: 0644]
LayoutTests/platform/ios-simulator-wk2/TestExpectations
LayoutTests/platform/mac-wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/applepay/ApplePaySession.cpp
Source/WebCore/Modules/applepay/ApplePaySession.h
Source/WebCore/Modules/applepay/ApplePaySession.idl
Source/WebCore/Modules/applepay/PaymentRequestValidator.cpp
Source/WebCore/Modules/applepay/PaymentRequestValidator.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/generic/IDLTypes.h
Source/WebCore/bindings/js/JSApplePaySessionCustom.cpp [deleted file]
Tools/ChangeLog
Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm

index e55c21b..b926ccc 100644 (file)
@@ -1,3 +1,23 @@
+2016-12-13  Sam Weinig  <sam@webkit.org>
+
+        [WebIDL] Remove use of Dictionary in ApplePaySession
+        https://bugs.webkit.org/show_bug.cgi?id=165787
+
+        Reviewed by Anders Carlsson.
+
+        * http/tests/ssl/applepay: Added.
+        * http/tests/ssl/applepay/ApplePaySession-expected.txt: Added.
+        * http/tests/ssl/applepay/ApplePaySession.html: Added.
+        Add a compressive test of the handling of the payment request to the ApplePaySession
+        constructor. For further testing, we will need to mock out bits of the underlying 
+        coordinator, but this allows for testing the aspect I am changing. The applepay
+        directory is in the ssl directory, as all use of ApplePay requires https.
+
+        * TestExpectations:
+        * platform/ios-simulator-wk2/TestExpectations:
+        * platform/mac-wk2/TestExpectations:
+        Only enable the tests on iOS 10.10 and greater, and macOS 10.12 and greater, WebKit2.
+
 2016-12-13  Daniel Bates  <dabates@apple.com>
 
         CSP: Teach the preload scanner about the 'nonce' attribute
index 1e24090..681cb6d 100644 (file)
@@ -77,6 +77,9 @@ fast/media/mq-inverted-colors-live-update-in-subframes.html [ Skip ]
 fast/media/mq-monochrome-live-update.html [ Skip ]
 fast/media/mq-prefers-reduced-motion-live-update.html [ Skip ]
 
+# ApplePay is only available on iOS (greater than iOS 10) and macOS (greater than macOS 10.12) and only for WebKit2.
+http/tests/ssl/applepay/ [ Skip ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific tests.
 #//////////////////////////////////////////////////////////////////////////////////////////
diff --git a/LayoutTests/http/tests/ssl/applepay/ApplePaySession-expected.txt b/LayoutTests/http/tests/ssl/applepay/ApplePaySession-expected.txt
new file mode 100644 (file)
index 0000000..f2ddfe1
--- /dev/null
@@ -0,0 +1,417 @@
+Test basic creation of an ApplePaySession object.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Testing PaymentRequest
+
+PASS new ApplePaySession(2, { }) threw exception TypeError: Member ApplePayPaymentRequest.countryCode is required and must be an instance of DOMString.
+PASS new ApplePaySession(2, validRequest()) did not throw exception.
+
+Testing PaymentRequest.countryCode
+
+SETUP: request = validRequest(); delete request.countryCode;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.countryCode is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.countryCode = 'invalid';
+PASS new ApplePaySession(2, request) threw exception TypeError: "invalid" is not a valid country code..
+
+SETUP: request = validRequest(); request.countryCode = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid country code..
+
+SETUP: request = validRequest(); request.countryCode = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: "null" is not a valid country code..
+
+SETUP: request = validRequest(); request.countryCode = undefined;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.countryCode is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.countryCode = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: "7" is not a valid country code..
+
+
+Testing PaymentRequest.currencyCode
+
+SETUP: request = validRequest(); delete request.currencyCode;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.currencyCode is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.currencyCode = 'invalid';
+PASS new ApplePaySession(2, request) threw exception TypeError: "invalid" is not a valid currency code..
+
+SETUP: request = validRequest(); request.currencyCode = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid currency code..
+
+SETUP: request = validRequest(); request.currencyCode = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: "null" is not a valid currency code..
+
+SETUP: request = validRequest(); request.currencyCode = undefined;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.currencyCode is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.currencyCode = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: "7" is not a valid currency code..
+
+
+Testing PaymentRequest.supportedNetworks
+
+SETUP: request = validRequest(); delete request.supportedNetworks;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.supportedNetworks is required and must be an instance of sequence.
+
+SETUP: request = validRequest(); request.supportedNetworks = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.supportedNetworks = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.supportedNetworks = undefined;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.supportedNetworks is required and must be an instance of sequence.
+
+SETUP: request = validRequest(); request.supportedNetworks = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.supportedNetworks = [];
+PASS new ApplePaySession(2, request) threw exception TypeError: At least one supported network must be provided..
+
+SETUP: request = validRequest(); request.supportedNetworks = ['invalidNetwork'];
+PASS new ApplePaySession(2, request) threw exception TypeError: "invalidNetwork" is not a valid payment network..
+
+SETUP: request = validRequest(); request.supportedNetworks = ['invalidNetwork', 'visa'];
+PASS new ApplePaySession(2, request) threw exception TypeError: "invalidNetwork" is not a valid payment network..
+
+SETUP: request = validRequest(); request.supportedNetworks = ['visa', 'visa'];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.merchantCapabilities
+
+SETUP: request = validRequest(); delete request.merchantCapabilities;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.merchantCapabilities is required and must be an instance of sequence.
+
+SETUP: request = validRequest(); request.merchantCapabilities = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.merchantCapabilities = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.merchantCapabilities = undefined;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.merchantCapabilities is required and must be an instance of sequence.
+
+SETUP: request = validRequest(); request.merchantCapabilities = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.merchantCapabilities = [];
+PASS new ApplePaySession(2, request) threw exception TypeError: At least one merchant capability must be provided..
+
+SETUP: request = validRequest(); request.merchantCapabilities = ['invalidCapability'];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.merchantCapabilities = ['invalidCapability', 'supports3DS'];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.merchantCapabilities = ['supports3DS', 'supports3DS'];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.total
+
+SETUP: request = validRequest(); delete request.total;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.total is required and must be an instance of ApplePayLineItem.
+
+SETUP: request = validRequest(); request.total = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.total = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.total = undefined;
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayPaymentRequest.total is required and must be an instance of ApplePayLineItem.
+
+SETUP: request = validRequest(); request.total = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.total = [];
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.total = { };
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.total = { label: 'label' };
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.total = { label: 'label', amount: 'amount' };
+PASS new ApplePaySession(2, request) threw exception TypeError: "amount" is not a valid amount..
+
+SETUP: request = validRequest(); request.total = { label: 'label', amount: '0' };
+PASS new ApplePaySession(2, request) threw exception TypeError: Total amount must be greater than zero..
+
+SETUP: request = validRequest(); request.total = { label: 'label', amount: '-10.00' };
+PASS new ApplePaySession(2, request) threw exception TypeError: Total amount must be greater than zero..
+
+SETUP: request = validRequest(); request.total = { label: 'label', amount: '10000000000.00' };
+PASS new ApplePaySession(2, request) threw exception TypeError: Total amount is too big..
+
+SETUP: request = validRequest(); request.total = { label: 'label', amount: '10.00', type: 'invalid' };
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.total = { label: 'label', amount: '10.00', type: 'pending' };
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.lineItems
+
+SETUP: request = validRequest(); request.lineItems = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.lineItems = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.lineItems = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.lineItems = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.lineItems = { };
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.lineItems = [];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.lineItems = [''];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.lineItems = [null];
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.lineItems = [undefined];
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.lineItems = [{}];
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.lineItems = [{ label: 'label' }];
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.lineItems = [{ label: 'label', amount: '' }];
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.lineItems = [{ label: 'label', amount: '10.00', type: 'invalid' }];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+Testing PaymentRequest.requiredBillingContactFields
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = { };
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = [];
+PASS new ApplePaySession(2, request) threw exception TypeError: At least one contact field must be provided..
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = [''];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = [null];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = [undefined];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = [{}];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = ['invalid'];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = ['email', 'name', 'phone', 'postalAddress'];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.requiredBillingContactFields = ['email', 'email'];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.billingContact
+
+SETUP: request = validRequest(); request.billingContact = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.billingContact = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.billingContact = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.billingContact = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.billingContact = { };
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.requiredShippingContactFields
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = { };
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = [];
+PASS new ApplePaySession(2, request) threw exception TypeError: At least one contact field must be provided..
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = [''];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = [null];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = [undefined];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = [{}];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = ['invalid'];
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = ['email', 'name', 'phone', 'postalAddress'];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.requiredShippingContactFields = ['email', 'email'];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.shippingContact
+
+SETUP: request = validRequest(); request.shippingContact = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingContact = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingContact = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingContact = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingContact = { };
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.shippingType
+
+SETUP: request = validRequest(); request.shippingType = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingType = 'shipping';
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingType = 'delivery';
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingType = 'storePickup';
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingType = 'servicePickup';
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingType = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingType = 'invalid';
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingType = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingType = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingType = { };
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+Testing PaymentRequest.shippingMethods
+
+SETUP: request = validRequest(); request.shippingMethods = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingMethods = '';
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.shippingMethods = 'invalid';
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.shippingMethods = null;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.shippingMethods = 7;
+PASS new ApplePaySession(2, request) threw exception TypeError: Value is not a sequence.
+
+SETUP: request = validRequest(); request.shippingMethods = { };
+PASS new ApplePaySession(2, request) threw exception TypeError: Type error.
+
+SETUP: request = validRequest(); request.shippingMethods = [];
+PASS new ApplePaySession(2, request) threw exception TypeError: At least one shipping method must be provided..
+
+SETUP: request = validRequest(); request.shippingMethods = [{ }];
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayShippingMethod.amount is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.shippingMethods = [{ amount: '', }];
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayShippingMethod.detail is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.shippingMethods = [{ amount: '', detail: '' }];
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayShippingMethod.identifier is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.shippingMethods = [{ amount: '', detail: '', identifier: '' }];
+PASS new ApplePaySession(2, request) threw exception TypeError: Member ApplePayShippingMethod.label is required and must be an instance of DOMString.
+
+SETUP: request = validRequest(); request.shippingMethods = [{ amount: '', detail: '', identifier: '', label: '' }];
+PASS new ApplePaySession(2, request) threw exception TypeError: "" is not a valid amount..
+
+SETUP: request = validRequest(); request.shippingMethods = [{ amount: '-1', detail: '', identifier: '', label: '' }];
+PASS new ApplePaySession(2, request) threw exception TypeError: Shipping method amount must be greater than or equal to zero..
+
+SETUP: request = validRequest(); request.shippingMethods = [{ amount: '10.00', detail: '', identifier: '', label: '' }];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.shippingMethods = [{ amount: '10.00', detail: '', identifier: '', label: '' }, { amount: '10.00', detail: '', identifier: '', label: '' }];
+PASS new ApplePaySession(2, request) did not throw exception.
+
+Testing PaymentRequest.applicationData
+
+SETUP: request = validRequest(); request.applicationData = undefined;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.applicationData = '';
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.applicationData = 'invalid';
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.applicationData = 7;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.applicationData = null;
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.applicationData = { };
+PASS new ApplePaySession(2, request) did not throw exception.
+
+SETUP: request = validRequest(); request.applicationData = { toString: function() { throw '"Error in toString"'; } };
+PASS new ApplePaySession(2, request) threw exception "Error in toString".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/ssl/applepay/ApplePaySession.html b/LayoutTests/http/tests/ssl/applepay/ApplePaySession.html
new file mode 100644 (file)
index 0000000..b5db27f
--- /dev/null
@@ -0,0 +1,243 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+
+description("Test basic creation of an ApplePaySession object.");
+
+window.jsTestIsAsync = true;
+
+function validRequest() {
+    return {
+          countryCode: 'US',
+          currencyCode: 'USD',
+          supportedNetworks: ['visa', 'masterCard'],
+          merchantCapabilities: ['supports3DS'],
+          total: { label: 'Your Label', amount: '10.00' },
+    }
+}
+
+function logAndShouldThrow(setup, test) {
+    debug("SETUP: " + setup)
+    eval(setup);
+    shouldThrow(test);
+    debug("")
+}
+
+function logAndShouldNotThrow(setup, test) {
+    debug("SETUP: " + setup)
+    eval(setup);
+    shouldNotThrow(test);
+    debug("")
+}
+
+function go() {
+    debug("Testing PaymentRequest")
+    debug("");
+    shouldThrow("new ApplePaySession(2, { })");
+    shouldNotThrow("new ApplePaySession(2, validRequest())");
+    debug("");
+    
+    debug("Testing PaymentRequest.countryCode")
+    debug("");
+    logAndShouldThrow("request = validRequest(); delete request.countryCode;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.countryCode = 'invalid';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.countryCode = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.countryCode = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.countryCode = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.countryCode = 7;", "new ApplePaySession(2, request)")
+    debug("");
+    
+    debug("Testing PaymentRequest.currencyCode")
+    debug("");
+    logAndShouldThrow("request = validRequest(); delete request.currencyCode;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.currencyCode = 'invalid';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.currencyCode = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.currencyCode = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.currencyCode = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.currencyCode = 7;", "new ApplePaySession(2, request)")
+    debug("");
+    
+    debug("Testing PaymentRequest.supportedNetworks")
+    debug("");
+    logAndShouldThrow("request = validRequest(); delete request.supportedNetworks;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.supportedNetworks = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.supportedNetworks = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.supportedNetworks = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.supportedNetworks = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.supportedNetworks = [];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.supportedNetworks = ['invalidNetwork'];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.supportedNetworks = ['invalidNetwork', 'visa'];", "new ApplePaySession(2, request)")
+    // FIXME: Should duplicate supportedNetworks be allowed?
+    logAndShouldNotThrow("request = validRequest(); request.supportedNetworks = ['visa', 'visa'];", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.merchantCapabilities")
+    debug("");
+    logAndShouldThrow("request = validRequest(); delete request.merchantCapabilities;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.merchantCapabilities = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.merchantCapabilities = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.merchantCapabilities = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.merchantCapabilities = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.merchantCapabilities = [];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.merchantCapabilities = ['invalidCapability'];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.merchantCapabilities = ['invalidCapability', 'supports3DS'];", "new ApplePaySession(2, request)")
+    // FIXME: Should duplicate merchantCapabilities be allowed?
+    logAndShouldNotThrow("request = validRequest(); request.merchantCapabilities = ['supports3DS', 'supports3DS'];", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.total")
+    debug("");
+    logAndShouldThrow("request = validRequest(); delete request.total;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = [];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = { };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = { label: 'label' };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = { label: 'label', amount: 'amount' };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = { label: 'label', amount: '0' };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = { label: 'label', amount: '-10.00' };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = { label: 'label', amount: '10000000000.00' };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.total = { label: 'label', amount: '10.00', type: 'invalid' };", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.total = { label: 'label', amount: '10.00', type: 'pending' };", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.lineItems")
+    debug("");
+    logAndShouldNotThrow("request = validRequest(); request.lineItems = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = { };", "new ApplePaySession(2, request)")
+    // FIXME: Should we allow an empty lineItems sequence?
+    logAndShouldNotThrow("request = validRequest(); request.lineItems = [];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = [''];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = [null];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = [undefined];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = [{}];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = [{ label: 'label' }];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = [{ label: 'label', amount: '' }];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.lineItems = [{ label: 'label', amount: '10.00', type: 'invalid' }];", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.requiredBillingContactFields")
+    debug("");
+    logAndShouldNotThrow("request = validRequest(); request.requiredBillingContactFields = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = { };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = [];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = [''];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = [null];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = [undefined];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = [{}];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredBillingContactFields = ['invalid'];", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.requiredBillingContactFields = ['email', 'name', 'phone', 'postalAddress'];", "new ApplePaySession(2, request)")
+    // FIXME: Should duplicate contactFields be allowed?
+    logAndShouldNotThrow("request = validRequest(); request.requiredBillingContactFields = ['email', 'email'];", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.billingContact")
+    debug("");
+    logAndShouldThrow("request = validRequest(); request.billingContact = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.billingContact = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.billingContact = 7;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.billingContact = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.billingContact = { };", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.requiredShippingContactFields")
+    debug("");
+    logAndShouldNotThrow("request = validRequest(); request.requiredShippingContactFields = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = { };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = [];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = [''];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = [null];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = [undefined];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = [{}];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.requiredShippingContactFields = ['invalid'];", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.requiredShippingContactFields = ['email', 'name', 'phone', 'postalAddress'];", "new ApplePaySession(2, request)")
+    // FIXME: Should duplicate contactFields be allowed?
+    logAndShouldNotThrow("request = validRequest(); request.requiredShippingContactFields = ['email', 'email'];", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.shippingContact")
+    debug("");
+    logAndShouldThrow("request = validRequest(); request.shippingContact = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingContact = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingContact = 7;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingContact = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingContact = { };", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.shippingType")
+    debug("");
+    logAndShouldNotThrow("request = validRequest(); request.shippingType = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingType = 'shipping';", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingType = 'delivery';", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingType = 'storePickup';", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingType = 'servicePickup';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingType = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingType = 'invalid';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingType = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingType = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingType = { };", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.shippingMethods")
+    debug("");
+    logAndShouldNotThrow("request = validRequest(); request.shippingMethods = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = '';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = 'invalid';", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = null;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = 7;", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = { };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = [];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = [{ }];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = [{ amount: '', }];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = [{ amount: '', detail: '' }];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = [{ amount: '', detail: '', identifier: '' }];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = [{ amount: '', detail: '', identifier: '', label: '' }];", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.shippingMethods = [{ amount: '-1', detail: '', identifier: '', label: '' }];", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingMethods = [{ amount: '10.00', detail: '', identifier: '', label: '' }];", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.shippingMethods = [{ amount: '10.00', detail: '', identifier: '', label: '' }, { amount: '10.00', detail: '', identifier: '', label: '' }];", "new ApplePaySession(2, request)")
+    
+    debug("Testing PaymentRequest.applicationData")
+    debug("");
+    logAndShouldNotThrow("request = validRequest(); request.applicationData = undefined;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.applicationData = '';", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.applicationData = 'invalid';", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.applicationData = 7;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.applicationData = null;", "new ApplePaySession(2, request)")
+    logAndShouldNotThrow("request = validRequest(); request.applicationData = { };", "new ApplePaySession(2, request)")
+    logAndShouldThrow("request = validRequest(); request.applicationData = { toString: function() { throw '\"Error in toString\"'; } };", "new ApplePaySession(2, request)")
+
+    document.querySelector("button").remove();
+
+    finishJSTest();
+}
+
+function clickElement(element) {
+    let x = element.offsetLeft + 2;
+    let y = element.offsetTop + 2;
+
+    var supportsTouchEvents = "TouchEvent" in window;
+    if (supportsTouchEvents && window.testRunner && testRunner.runUIScript) {
+        testRunner.runUIScript(`(function() { uiController.singleTapAtPoint(${x}, ${y}, function() { }); })();`, function () { });
+    } else if (window.eventSender) {
+        eventSender.mouseMoveTo(x, y);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+    }
+}
+
+window.onload = function() {
+    clickElement(document.querySelector("button"));
+}
+
+</script>
+<button onclick='go()'>Go</button>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 4214756..779b865 100644 (file)
@@ -16,6 +16,8 @@ fast/media/mq-inverted-colors-live-update-in-subframes.html [ Pass ]
 fast/media/mq-monochrome-live-update.html [ Pass ]
 fast/media/mq-prefers-reduced-motion-live-update.html [ Pass ]
 
+http/tests/ssl/applepay/ [ Pass ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific directories.
 #//////////////////////////////////////////////////////////////////////////////////////////
index b492fb2..ca811d7 100644 (file)
@@ -21,6 +21,8 @@ fast/media/mq-prefers-reduced-motion-live-update.html [ Pass ]
 
 pointer-lock/lock-lost-on-esc-in-fullscreen.html [ Pass ]
 
+[ Sierra+ ] http/tests/ssl/applepay/ [ Pass ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific directories.
 #//////////////////////////////////////////////////////////////////////////////////////////
index e130ff9..41d5c99 100644 (file)
@@ -1,3 +1,95 @@
+2016-12-12  Sam Weinig  <sam@webkit.org>
+
+        [WebIDL] Remove use of Dictionary in ApplePaySession
+        https://bugs.webkit.org/show_bug.cgi?id=165787
+
+        Reviewed by Anders Carlsson.
+
+        First take at generating the bindings for ApplePaySession and removing
+        all use of Dictionary.
+        
+        - Removes all use of Dictionary!
+        - Removes use of logging errors to the console with improved Exception messages.
+        - Use ExceptionOr extensively to pass exception state.
+        
+        Still to do:
+            - Reconcile / merge ApplePaySession::PaymentRequest with WebCore::PaymentRequest
+              and all the sub-objects held within.
+            - Remove PaymentRequestValidator entirely, merging validation into the validation
+              we already do in ApplePaySession.cpp
+            - Make ApplePayEvents use generated dictionary creation code.
+
+        Test: http/tests/ssl/applepay/ApplePaySession.html
+
+        * Modules/applepay/ApplePaySession.cpp:
+        (WebCore::convertAndValidate):
+        (WebCore::canCallApplePaySessionAPIs):
+        (WebCore::ApplePaySession::create):
+        (WebCore::ApplePaySession::ApplePaySession):
+        (WebCore::ApplePaySession::supportsVersion):
+        (WebCore::ApplePaySession::canMakePayments):
+        (WebCore::ApplePaySession::canMakePaymentsWithActiveCard):
+        (WebCore::ApplePaySession::openPaymentSetup):
+        (WebCore::ApplePaySession::begin):
+        (WebCore::ApplePaySession::completeMerchantValidation):
+        (WebCore::ApplePaySession::completeShippingMethodSelection):
+        (WebCore::ApplePaySession::completeShippingContactSelection):
+        (WebCore::ApplePaySession::completePaymentMethodSelection):
+        (WebCore::ApplePaySession::didSelectShippingMethod):
+        (WebCore::createContactFields): Deleted.
+        (WebCore::toLineItemType): Deleted.
+        (WebCore::isValidLineItemPropertyName): Deleted.
+        (WebCore::createLineItem): Deleted.
+        (WebCore::createLineItems): Deleted.
+        (WebCore::createMerchantCapabilities): Deleted.
+        (WebCore::createSupportedNetworks): Deleted.
+        (WebCore::toShippingType): Deleted.
+        (WebCore::isValidShippingMethodPropertyName): Deleted.
+        (WebCore::createShippingMethod): Deleted.
+        (WebCore::createShippingMethods): Deleted.
+        (WebCore::isValidPaymentRequestPropertyName): Deleted.
+        (WebCore::createPaymentRequest): Deleted.
+        * Modules/applepay/ApplePaySession.h:
+        Replace hand written dictionary extraction code with autogenerated code
+        and hand written additional validation.
+
+        * Modules/applepay/ApplePaySession.idl:
+        Add helper dictionaries and enums.
+
+        * Modules/applepay/PaymentRequestValidator.cpp:
+        (WebCore::PaymentRequestValidator::validate):
+        (WebCore::PaymentRequestValidator::validateTotal):
+        (WebCore::validateCountryCode):
+        (WebCore::validateCurrencyCode):
+        (WebCore::validateMerchantCapabilities):
+        (WebCore::validateSupportedNetworks):
+        (WebCore::validateShippingMethod):
+        (WebCore::validateShippingMethods):
+        (WebCore::PaymentRequestValidator::PaymentRequestValidator): Deleted.
+        (WebCore::PaymentRequestValidator::~PaymentRequestValidator): Deleted.
+        (WebCore::PaymentRequestValidator::validateCountryCode): Deleted.
+        (WebCore::PaymentRequestValidator::validateCurrencyCode): Deleted.
+        (WebCore::PaymentRequestValidator::validateMerchantCapabilities): Deleted.
+        (WebCore::PaymentRequestValidator::validateShippingMethod): Deleted.
+        (WebCore::PaymentRequestValidator::validateSupportedNetworks): Deleted.
+        (WebCore::PaymentRequestValidator::validateShippingMethods): Deleted.
+        * Modules/applepay/PaymentRequestValidator.h:
+        Instead of reporting the validation errors to the console, pass them in the exception.
+        This allows us to remove the window member, and move the helpers to the implementation
+        file as statics.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        Remove file.
+
+        * bindings/generic/IDLTypes.h:
+        (WebCore::IDLObject::nullValue):
+        (WebCore::IDLObject::isNullValue):
+        (WebCore::IDLObject::extractValueFromNullable):
+        Add nullability traits for IDLObject.
+        
+        * bindings/js/JSApplePaySessionCustom.cpp:
+        Removed.
+
 2016-12-13  Daniel Bates  <dabates@apple.com>
 
         CSP: Teach the preload scanner about the 'nonce' attribute
index fe6067e..17efa9b 100644 (file)
 #include "ApplePayShippingContactSelectedEvent.h"
 #include "ApplePayShippingMethodSelectedEvent.h"
 #include "ApplePayValidateMerchantEvent.h"
-#include "ArrayValue.h"
-#include "DOMWindow.h"
-#include "Dictionary.h"
 #include "Document.h"
 #include "DocumentLoader.h"
 #include "EventNames.h"
 #include "JSDOMPromise.h"
-#include "JSMainThreadExecState.h"
 #include "LinkIconCollector.h"
 #include "LinkIconType.h"
 #include "MainFrame.h"
@@ -163,433 +159,212 @@ static std::optional<int64_t> parseAmount(const String& amountString)
     return amount;
 }
 
-static std::optional<PaymentRequest::ContactFields> createContactFields(DOMWindow& window, const ArrayValue& contactFieldsArray)
+static ExceptionOr<PaymentRequest::LineItem> convertAndValidate(ApplePaySession::LineItem&& lineItem)
 {
-    PaymentRequest::ContactFields result;
-
-    size_t contactFieldsCount;
-    if (!contactFieldsArray.length(contactFieldsCount))
-        return std::nullopt;
-
-    for (size_t i = 0; i < contactFieldsCount; ++i) {
-        String contactField;
-        if (!contactFieldsArray.get(i, contactField))
-            return std::nullopt;
-
-        if (contactField == "postalAddress")
-            result.postalAddress = true;
-        else if (contactField == "phone")
-            result.phone = true;
-        else if (contactField == "email")
-            result.email = true;
-        else if (contactField == "name")
-            result.name = true;
-        else {
-            auto message = makeString("\"" + contactField, "\" is not a valid contact field.");
-            window.printErrorMessage(message);
-            return std::nullopt;
-        }
-    }
-
-    return result;
-}
-
-static std::optional<PaymentRequest::LineItem::Type> toLineItemType(const String& type)
-{
-    if (type == "pending")
-        return PaymentRequest::LineItem::Type::Pending;
-    if (type == "final")
-        return PaymentRequest::LineItem::Type::Final;
-
-    return std::nullopt;
-}
-
-static bool isValidLineItemPropertyName(const String& propertyName)
-{
-    const char* validPropertyNames[] = {
-        "type",
-        "label",
-        "amount",
-    };
-
-    for (auto& validPropertyName : validPropertyNames) {
-        if (propertyName == validPropertyName)
-            return true;
-    }
-
-    return false;
-}
+    auto amount = parseAmount(lineItem.amount);
+    if (!amount)
+        return Exception { TypeError, makeString("\"" + lineItem.amount, "\" is not a valid amount.") };
 
-static std::optional<PaymentRequest::LineItem> createLineItem(DOMWindow& window, const Dictionary& total)
-{
-    Vector<String> propertyNames;
-    total.getOwnPropertyNames(propertyNames);
-
-    for (auto& propertyName : propertyNames) {
-        if (!isValidLineItemPropertyName(propertyName)) {
-            auto message = makeString("\"" + propertyName, "\" is not a valid line item property name.");
-            window.printErrorMessage(message);
-            return std::nullopt;
-        }
-    }
-
-    // Line item type defaults to Final.
     PaymentRequest::LineItem result;
+    result.amount = *amount;
+    result.type = lineItem.type;
+    result.label = lineItem.label;
 
-    if (auto typeString = total.get<String>("type")) {
-        auto type = toLineItemType(*typeString);
-        if (!type) {
-            auto message = makeString("\"" + *typeString, "\" is not a valid line item type.");
-            window.printErrorMessage(message);
-            return std::nullopt;
-        }
-
-        result.type = *type;
-    }
-
-    if (auto label = total.get<String>("label"))
-        result.label = *label;
-    if (auto amountString = total.get<String>("amount")) {
-        if (auto amount = parseAmount(*amountString))
-            result.amount = *amount;
-        else {
-            auto message = makeString("\"" + *amountString, "\" is not a valid amount.");
-            window.printErrorMessage(message);
-            return std::nullopt;
-        }
-    }
-
-    return result;
+    return WTFMove(result);
 }
 
-static std::optional<Vector<PaymentRequest::LineItem>> createLineItems(DOMWindow& window, const ArrayValue& lineItemsArray)
+static ExceptionOr<Vector<PaymentRequest::LineItem>> convertAndValidate(Vector<ApplePaySession::LineItem>&& lineItems)
 {
     Vector<PaymentRequest::LineItem> result;
-
-    size_t lineItemCount;
-    if (!lineItemsArray.length(lineItemCount))
-        return std::nullopt;
-
-    for (size_t i = 0; i < lineItemCount; ++i) {
-        Dictionary lineItemDictionary;
-        if (!lineItemsArray.get(i, lineItemDictionary))
-            return std::nullopt;
-
-        if (auto lineItem = createLineItem(window, lineItemDictionary))
-            result.append(*lineItem);
+    result.reserveInitialCapacity(lineItems.size());
+    
+    for (auto lineItem : lineItems) {
+        auto convertedLineItem = convertAndValidate(WTFMove(lineItem));
+        if (convertedLineItem.hasException())
+            return convertedLineItem.releaseException();
+        result.uncheckedAppend(convertedLineItem.releaseReturnValue());
     }
 
-    return result;
+    return WTFMove(result);
 }
 
-static std::optional<PaymentRequest::MerchantCapabilities> createMerchantCapabilities(DOMWindow& window, const ArrayValue& merchantCapabilitiesArray)
+static ExceptionOr<PaymentRequest::MerchantCapabilities> convertAndValidate(Vector<ApplePaySession::MerchantCapability>&& merchantCapabilities)
 {
-    PaymentRequest::MerchantCapabilities result;
-
-    size_t merchantCapabilitiesCount;
-    if (!merchantCapabilitiesArray.length(merchantCapabilitiesCount))
-        return std::nullopt;
+    if (merchantCapabilities.isEmpty())
+        return Exception { TypeError, "At least one merchant capability must be provided." };
 
-    for (size_t i = 0; i < merchantCapabilitiesCount; ++i) {
-        String merchantCapability;
-        if (!merchantCapabilitiesArray.get(i, merchantCapability))
-            return std::nullopt;
+    PaymentRequest::MerchantCapabilities result;
 
-        if (merchantCapability == "supports3DS")
+    for (auto& merchantCapability : merchantCapabilities) {
+        switch (merchantCapability) {
+        case ApplePaySession::MerchantCapability::Supports3DS:
             result.supports3DS = true;
-        else if (merchantCapability == "supportsEMV")
+            break;
+        case ApplePaySession::MerchantCapability::SupportsEMV:
             result.supportsEMV = true;
-        else if (merchantCapability == "supportsCredit")
+            break;
+        case ApplePaySession::MerchantCapability::SupportsCredit:
             result.supportsCredit = true;
-        else if (merchantCapability == "supportsDebit")
+            break;
+        case ApplePaySession::MerchantCapability::SupportsDebit:
             result.supportsDebit = true;
-        else {
-            auto message = makeString("\"" + merchantCapability, "\" is not a valid merchant capability.");
-            window.printErrorMessage(message);
-            return std::nullopt;
+            break;
         }
     }
 
-    return result;
+    return WTFMove(result);
 }
 
-static std::optional<Vector<String>> createSupportedNetworks(unsigned version, DOMWindow& window, const ArrayValue& supportedNetworksArray)
+static ExceptionOr<Vector<String>> convertAndValidate(unsigned version, Vector<String>&& supportedNetworks)
 {
-    Vector<String> result;
-
-    size_t supportedNetworksCount;
-    if (!supportedNetworksArray.length(supportedNetworksCount))
-        return std::nullopt;
+    if (supportedNetworks.isEmpty())
+        return Exception { TypeError, "At least one supported network must be provided." };
 
-    for (size_t i = 0; i < supportedNetworksCount; ++i) {
-        String supportedNetwork;
-        if (!supportedNetworksArray.get(i, supportedNetwork))
-            return std::nullopt;
-
-        if (!PaymentRequest::isValidSupportedNetwork(version, supportedNetwork)) {
-            auto message = makeString("\"" + supportedNetwork, "\" is not a valid payment network.");
-            window.printErrorMessage(message);
-            return std::nullopt;
-        }
-
-        result.append(WTFMove(supportedNetwork));
+    for (auto& supportedNetwork : supportedNetworks) {
+        if (!PaymentRequest::isValidSupportedNetwork(version, supportedNetwork))
+            return Exception { TypeError, makeString("\"" + supportedNetwork, "\" is not a valid payment network.") };
     }
 
-    return result;
-}
-
-static std::optional<PaymentRequest::ShippingType> toShippingType(const String& shippingTypeString)
-{
-    if (shippingTypeString == "shipping")
-        return PaymentRequest::ShippingType::Shipping;
-    if (shippingTypeString == "delivery")
-        return PaymentRequest::ShippingType::Delivery;
-    if (shippingTypeString == "storePickup")
-        return PaymentRequest::ShippingType::StorePickup;
-    if (shippingTypeString == "servicePickup")
-        return PaymentRequest::ShippingType::ServicePickup;
-
-    return std::nullopt;
+    return WTFMove(supportedNetworks);
 }
 
-static bool isValidShippingMethodPropertyName(const String& propertyName)
+static ExceptionOr<PaymentRequest::ContactFields> convertAndValidate(Vector<ApplePaySession::ContactField>&& contactFields)
 {
-    const char* validPropertyNames[] = {
-        "label",
-        "detail",
-        "amount",
-        "identifier",
-    };
-
-    for (auto& validPropertyName : validPropertyNames) {
-        if (propertyName == validPropertyName)
-            return true;
-    }
-
-    return false;
-}
+    if (contactFields.isEmpty())
+        return Exception { TypeError, "At least one contact field must be provided." };
 
-static std::optional<PaymentRequest::ShippingMethod> createShippingMethod(DOMWindow& window, const Dictionary& shippingMethodDictionary)
-{
-    Vector<String> propertyNames;
-    shippingMethodDictionary.getOwnPropertyNames(propertyNames);
+    PaymentRequest::ContactFields result;
 
-    for (auto& propertyName : propertyNames) {
-        if (!isValidShippingMethodPropertyName(propertyName)) {
-            auto message = makeString("\"" + propertyName, "\" is not a valid shipping method property name.");
-            window.printErrorMessage(message);
-            return std::nullopt;
+    for (auto& contactField : contactFields) {
+        switch (contactField) {
+        case ApplePaySession::ContactField::Email:
+            result.email = true;
+            break;
+        case ApplePaySession::ContactField::Name:
+            result.name = true;
+            break;
+        case ApplePaySession::ContactField::Phone:
+            result.phone = true;
+            break;
+        case ApplePaySession::ContactField::PostalAddress:
+            result.postalAddress = true;
+            break;
         }
     }
 
-    PaymentRequest::ShippingMethod result;
-
-    auto label = shippingMethodDictionary.get<String>("label");
-    if (!label) {
-        window.printErrorMessage("Missing shipping method label.");
-        return std::nullopt;
-    }
-    result.label = *label;
-
-    auto detail = shippingMethodDictionary.get<String>("detail");
-    if (!detail) {
-        window.printErrorMessage("Missing shipping method detail.");
-        return std::nullopt;
-    }
-    result.detail = *detail;
-
-    auto amountString = shippingMethodDictionary.get<String>("amount");
-    if (!amountString) {
-        window.printErrorMessage("Missing shipping method amount.");
-        return std::nullopt;
-    }
-
-    if (auto amount = parseAmount(*amountString))
-        result.amount = *amount;
-    else {
-        auto message = makeString("\"" + *amountString, "\" is not a valid amount.");
-        window.printErrorMessage(message);
-        return std::nullopt;
-    }
-
-    auto identifier = shippingMethodDictionary.get<String>("identifier");
-    if (!identifier) {
-        window.printErrorMessage("Missing shipping method identifier.");
-        return std::nullopt;
-    }
-    result.identifier = *identifier;
-
-    return result;
+    return WTFMove(result);
 }
 
-static std::optional<Vector<PaymentRequest::ShippingMethod>> createShippingMethods(DOMWindow& window, const ArrayValue& shippingMethodsArray)
+static ExceptionOr<PaymentRequest::ShippingMethod> convertAndValidate(ApplePaySession::ShippingMethod&& shippingMethod)
 {
-    Vector<PaymentRequest::ShippingMethod> result;
-
-    size_t shippingMethodCount;
-    if (!shippingMethodsArray.length(shippingMethodCount))
-        return std::nullopt;
+    auto amount = parseAmount(shippingMethod.amount);
+    if (!amount)
+        return Exception { TypeError, makeString("\"" + shippingMethod.amount, "\" is not a valid amount.") };
 
-    for (size_t i = 0; i < shippingMethodCount; ++i) {
-        Dictionary shippingMethodDictionary;
-        if (!shippingMethodsArray.get(i, shippingMethodDictionary))
-            return std::nullopt;
-
-        if (auto shippingMethod = createShippingMethod(window, shippingMethodDictionary))
-            result.append(*shippingMethod);
-        else
-            return std::nullopt;
-    }
+    PaymentRequest::ShippingMethod result;
+    result.amount = *amount;
+    result.label = shippingMethod.label;
+    result.detail = shippingMethod.detail;
+    result.identifier = shippingMethod.identifier;
 
-    return result;
+    return WTFMove(result);
 }
 
-static bool isValidPaymentRequestPropertyName(const String& propertyName)
+static ExceptionOr<Vector<PaymentRequest::ShippingMethod>> convertAndValidate(Vector<ApplePaySession::ShippingMethod>&& shippingMethods)
 {
-    const char* validPropertyNames[] = {
-        "merchantCapabilities",
-        "supportedNetworks",
-        "countryCode",
-        "currencyCode",
-        "requiredBillingContactFields",
-        "billingContact",
-        "requiredShippingContactFields",
-        "shippingContact",
-        "shippingType",
-        "shippingMethods",
-        "total",
-        "lineItems",
-        "applicationData",
-    };
+    if (shippingMethods.isEmpty())
+        return Exception { TypeError, "At least one shipping method must be provided." };
 
-    for (auto& validPropertyName : validPropertyNames) {
-        if (propertyName == validPropertyName)
-            return true;
+    Vector<PaymentRequest::ShippingMethod> result;
+    result.reserveInitialCapacity(shippingMethods.size());
+    
+    for (auto& shippingMethod : shippingMethods) {
+        auto convertedShippingMethod = convertAndValidate(WTFMove(shippingMethod));
+        if (convertedShippingMethod.hasException())
+            return convertedShippingMethod.releaseException();
+        result.uncheckedAppend(convertedShippingMethod.releaseReturnValue());
     }
 
-    return false;
+    return WTFMove(result);
 }
 
-static std::optional<PaymentRequest> createPaymentRequest(unsigned version, DOMWindow& window, const Dictionary& dictionary)
+static ExceptionOr<PaymentRequest> convertAndValidate(JSC::ExecState& state, unsigned version, ApplePaySession::PaymentRequest&& paymentRequest)
 {
-    PaymentRequest paymentRequest;
-
-    Vector<String> propertyNames;
-    dictionary.getOwnPropertyNames(propertyNames);
-
-    for (auto& propertyName : propertyNames) {
-        if (propertyName == "requiredShippingAddressFields") {
-            window.printErrorMessage("\"requiredShippingAddressFields\" has been deprecated. Please switch to \"requiredShippingContactFields\" instead.");
-            return std::nullopt;
-        }
-
-        if (propertyName == "requiredBillingAddressFields") {
-            window.printErrorMessage("\"requiredBillingAddressFields\" has been deprecated. Please switch to \"requiredBillingContactFields\" instead.");
-            return std::nullopt;
-        }
+    PaymentRequest result;
 
-        if (!isValidPaymentRequestPropertyName(propertyName)) {
-            auto message = makeString("\"" + propertyName, "\" is not a valid payment request property name.");
-            window.printErrorMessage(message);
-            return std::nullopt;
-        }
-    }
+    auto total = convertAndValidate(WTFMove(paymentRequest.total));
+    if (total.hasException())
+        return total.releaseException();
+    result.setTotal(total.releaseReturnValue());
 
-    if (auto merchantCapabilitiesArray = dictionary.get<ArrayValue>("merchantCapabilities")) {
-        auto merchantCapabilities = createMerchantCapabilities(window, *merchantCapabilitiesArray);
-        if (!merchantCapabilities)
-            return std::nullopt;
+    // FIXME: Should this swallow exceptions like the old code seemed to do?
+    auto lineItems = convertAndValidate(WTFMove(paymentRequest.lineItems));
+    if (lineItems.hasException())
+        return lineItems.releaseException();
+    result.setLineItems(lineItems.releaseReturnValue());
 
-        paymentRequest.setMerchantCapabilities(*merchantCapabilities);
-    }
+    result.setCountryCode(paymentRequest.countryCode);
+    result.setCurrencyCode(paymentRequest.currencyCode);
 
-    if (auto supportedNetworksArray = dictionary.get<ArrayValue>("supportedNetworks")) {
-        auto supportedNetworks = createSupportedNetworks(version, window, *supportedNetworksArray);
-        if (!supportedNetworks)
-            return std::nullopt;
-
-        paymentRequest.setSupportedNetworks(*supportedNetworks);
-    }
+    auto merchantCapabilities = convertAndValidate(WTFMove(paymentRequest.merchantCapabilities));
+    if (merchantCapabilities.hasException())
+        return merchantCapabilities.releaseException();
+    result.setMerchantCapabilities(merchantCapabilities.releaseReturnValue());
 
-    if (auto countryCode = dictionary.get<String>("countryCode"))
-        paymentRequest.setCountryCode(*countryCode);
-    if (auto currencyCode = dictionary.get<String>("currencyCode"))
-        paymentRequest.setCurrencyCode(*currencyCode);
+    auto supportedNetworks = convertAndValidate(version, WTFMove(paymentRequest.supportedNetworks));
+    if (supportedNetworks.hasException())
+        return supportedNetworks.releaseException();
+    result.setSupportedNetworks(supportedNetworks.releaseReturnValue());
 
-    if (auto requiredBillingContactFieldsArray = dictionary.get<ArrayValue>("requiredBillingContactFields")) {
-        auto requiredBillingContactFields = createContactFields(window, *requiredBillingContactFieldsArray);
-        if (!requiredBillingContactFields)
-            return std::nullopt;
-
-        paymentRequest.setRequiredBillingContactFields(*requiredBillingContactFields);
+    if (paymentRequest.requiredBillingContactFields) {
+        auto requiredBillingContactFields = convertAndValidate(WTFMove(*paymentRequest.requiredBillingContactFields));
+        if (requiredBillingContactFields.hasException())
+            return requiredBillingContactFields.releaseException();
+        result.setRequiredBillingContactFields(requiredBillingContactFields.releaseReturnValue());
     }
 
-    if (auto billingContactValue = dictionary.get<JSC::JSValue>("billingContact")) {
+    if (paymentRequest.billingContact) {
         String errorMessage;
-        auto billingContact = PaymentContact::fromJS(*JSMainThreadExecState::currentState(), *billingContactValue, errorMessage);
-        if (!billingContact) {
-            window.printErrorMessage(errorMessage);
-            return std::nullopt;
-        }
+        auto billingContact = PaymentContact::fromJS(state, paymentRequest.billingContact.get(), errorMessage);
+        if (!billingContact)
+            return Exception { TypeError, WTFMove(errorMessage) };
 
-        paymentRequest.setBillingContact(*billingContact);
+        result.setBillingContact(*billingContact);
     }
 
-    if (auto requiredShippingContactFieldsArray = dictionary.get<ArrayValue>("requiredShippingContactFields")) {
-        auto requiredShippingContactFields = createContactFields(window, *requiredShippingContactFieldsArray);
-        if (!requiredShippingContactFields)
-            return std::nullopt;
-
-        paymentRequest.setRequiredShippingContactFields(*requiredShippingContactFields);
+    if (paymentRequest.requiredShippingContactFields) {
+        auto requiredShippingContactFields = convertAndValidate(WTFMove(*paymentRequest.requiredShippingContactFields));
+        if (requiredShippingContactFields.hasException())
+            return requiredShippingContactFields.releaseException();
+        result.setRequiredShippingContactFields(requiredShippingContactFields.releaseReturnValue());
     }
 
-    if (auto shippingContactValue = dictionary.get<JSC::JSValue>("shippingContact")) {
+    if (paymentRequest.shippingContact) {
         String errorMessage;
-        auto shippingContact = PaymentContact::fromJS(*JSMainThreadExecState::currentState(), *shippingContactValue, errorMessage);
-        if (!shippingContact) {
-            window.printErrorMessage(errorMessage);
-            return std::nullopt;
-        }
+        auto shippingContact = PaymentContact::fromJS(state, paymentRequest.shippingContact.get(), errorMessage);
+        if (!shippingContact)
+            return Exception { TypeError, WTFMove(errorMessage) };
 
-        paymentRequest.setShippingContact(*shippingContact);
+        result.setBillingContact(*shippingContact);
     }
 
-    if (auto shippingTypeString = dictionary.get<String>("shippingType")) {
-        auto shippingType = toShippingType(*shippingTypeString);
+    result.setShippingType(paymentRequest.shippingType);
 
-        if (!shippingType) {
-            auto message = makeString("\"" + *shippingTypeString, "\" is not a valid shipping type.");
-            window.printErrorMessage(message);
-            return std::nullopt;
-        }
-        paymentRequest.setShippingType(*shippingType);
+    if (paymentRequest.shippingMethods) {
+        auto shippingMethods = convertAndValidate(WTFMove(*paymentRequest.shippingMethods));
+        if (shippingMethods.hasException())
+            return shippingMethods.releaseException();
+        result.setShippingMethods(shippingMethods.releaseReturnValue());
     }
 
-    if (auto shippingMethodsArray = dictionary.get<ArrayValue>("shippingMethods")) {
-        auto shippingMethods = createShippingMethods(window, *shippingMethodsArray);
-        if (!shippingMethods)
-            return std::nullopt;
-
-        paymentRequest.setShippingMethods(*shippingMethods);
-    }
+    result.setApplicationData(paymentRequest.applicationData);
 
-    if (auto totalDictionary = dictionary.get<Dictionary>("total")) {
-        auto total = createLineItem(window, *totalDictionary);
-        if (!total)
-            return std::nullopt;
-
-        paymentRequest.setTotal(*total);
-    }
+    // FIXME: Merge this validation into the validation we are doing above.
+    auto validatedPaymentRequest = PaymentRequestValidator::validate(result);
+    if (validatedPaymentRequest.hasException())
+        return validatedPaymentRequest.releaseException();
 
-    if (auto lineItemsArray = dictionary.get<ArrayValue>("lineItems")) {
-        if (auto lineItems = createLineItems(window, *lineItemsArray))
-            paymentRequest.setLineItems(*lineItems);
-    }
-
-    if (auto applicationData = dictionary.get<String>("applicationData"))
-        paymentRequest.setApplicationData(*applicationData);
-
-    return paymentRequest;
+    return WTFMove(result);
 }
 
 static bool isSecure(DocumentLoader& documentLoader)
@@ -603,71 +378,52 @@ static bool isSecure(DocumentLoader& documentLoader)
     return true;
 }
 
-static bool canCallApplePaySessionAPIs(Document& document, String& errorMessage)
+static ExceptionOr<void> canCallApplePaySessionAPIs(Document& document)
 {
-    if (!isSecure(*document.loader())) {
-        errorMessage = "Trying to call an ApplePaySession API from an insecure document.";
-        return false;
-    }
+    if (!isSecure(*document.loader()))
+        return Exception { INVALID_ACCESS_ERR, "Trying to call an ApplePaySession API from an insecure document." };
 
     auto& topDocument = document.topDocument();
     if (&document != &topDocument) {
         auto& topOrigin = *topDocument.topOrigin();
 
-        if (!document.securityOrigin()->isSameSchemeHostPort(&topOrigin)) {
-            errorMessage = "Trying to call an ApplePaySession API from a document with an different security origin than its top-level frame.";
-            return false;
-        }
+        if (!document.securityOrigin()->isSameSchemeHostPort(&topOrigin))
+            return Exception { INVALID_ACCESS_ERR, "Trying to call an ApplePaySession API from a document with an different security origin than its top-level frame." };
 
         for (auto* ancestorDocument = document.parentDocument(); ancestorDocument != &topDocument; ancestorDocument = ancestorDocument->parentDocument()) {
-            if (!isSecure(*ancestorDocument->loader())) {
-                errorMessage = "Trying to call an ApplePaySession API from a document with an insecure parent frame.";
-                return false;
-            }
+            if (!isSecure(*ancestorDocument->loader()))
+                return Exception { INVALID_ACCESS_ERR, "Trying to call an ApplePaySession API from a document with an insecure parent frame." };
 
-            if (!ancestorDocument->securityOrigin()->isSameSchemeHostPort(&topOrigin)) {
-                errorMessage = "Trying to call an ApplePaySession API from a document with an different security origin than its top-level frame.";
-                return false;
-            }
+            if (!ancestorDocument->securityOrigin()->isSameSchemeHostPort(&topOrigin))
+                return Exception { INVALID_ACCESS_ERR, "Trying to call an ApplePaySession API from a document with an different security origin than its top-level frame." };
         }
     }
 
-    return true;
+    return { };
 }
 
-ExceptionOr<Ref<ApplePaySession>> ApplePaySession::create(JSC::ExecState& state, Document& document, unsigned version, JSC::JSValue arguments)
+ExceptionOr<Ref<ApplePaySession>> ApplePaySession::create(JSC::ExecState& state, Document& document, unsigned version, ApplePaySession::PaymentRequest&& paymentRequest)
 {
-    DOMWindow& window = *document.domWindow();
-
-    String errorMessage;
-    if (!canCallApplePaySessionAPIs(document, errorMessage)) {
-        window.printErrorMessage(errorMessage);
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    auto canCall = canCallApplePaySessionAPIs(document);
+    if (canCall.hasException())
+        return canCall.releaseException();
 
-    if (!ScriptController::processingUserGesture()) {
-        window.printErrorMessage("Must create a new ApplePaySession from a user gesture handler.");
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    if (!ScriptController::processingUserGesture())
+        return Exception { INVALID_ACCESS_ERR, "Must create a new ApplePaySession from a user gesture handler." };
 
     auto& paymentCoordinator = document.frame()->mainFrame().paymentCoordinator();
 
-    if (!version || !paymentCoordinator.supportsVersion(version)) {
-        window.printErrorMessage(makeString("\"" + String::number(version), "\" is not a supported version."));
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    if (!version || !paymentCoordinator.supportsVersion(version))
+        return Exception { INVALID_ACCESS_ERR, makeString("\"" + String::number(version), "\" is not a supported version.") };
 
-    auto paymentRequest = createPaymentRequest(version, window, { &state, arguments });
-    if (!paymentRequest)
-        return Exception { TYPE_MISMATCH_ERR };
+    auto convertedPaymentRequest = convertAndValidate(state, version, WTFMove(paymentRequest));
+    if (convertedPaymentRequest.hasException())
+        return convertedPaymentRequest.releaseException();
 
-    if (!PaymentRequestValidator(window).validate(*paymentRequest))
-        return Exception { INVALID_ACCESS_ERR };
-
-    return adoptRef(*new ApplePaySession(document, WTFMove(*paymentRequest)));
+    return adoptRef(*new ApplePaySession(document, convertedPaymentRequest.releaseReturnValue()));
 }
 
-ApplePaySession::ApplePaySession(Document& document, PaymentRequest&& paymentRequest)
+ApplePaySession::ApplePaySession(Document& document, WebCore::PaymentRequest&& paymentRequest)
     : ActiveDOMObject(&document)
     , m_paymentRequest(WTFMove(paymentRequest))
 {
@@ -684,13 +440,10 @@ ExceptionOr<bool> ApplePaySession::supportsVersion(ScriptExecutionContext& scrip
         return Exception { INVALID_ACCESS_ERR };
 
     auto& document = downcast<Document>(scriptExecutionContext);
-    DOMWindow& window = *document.domWindow();
 
-    String errorMessage;
-    if (!canCallApplePaySessionAPIs(document, errorMessage)) {
-        window.printErrorMessage(errorMessage);
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    auto canCall = canCallApplePaySessionAPIs(document);
+    if (canCall.hasException())
+        return canCall.releaseException();
 
     return document.frame()->mainFrame().paymentCoordinator().supportsVersion(version);
 }
@@ -707,13 +460,10 @@ static bool shouldDiscloseApplePayCapability(Document& document)
 ExceptionOr<bool> ApplePaySession::canMakePayments(ScriptExecutionContext& scriptExecutionContext)
 {
     auto& document = downcast<Document>(scriptExecutionContext);
-    DOMWindow& window = *document.domWindow();
 
-    String errorMessage;
-    if (!canCallApplePaySessionAPIs(document, errorMessage)) {
-        window.printErrorMessage(errorMessage);
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    auto canCall = canCallApplePaySessionAPIs(document);
+    if (canCall.hasException())
+        return canCall.releaseException();
 
     return document.frame()->mainFrame().paymentCoordinator().canMakePayments();
 }
@@ -721,13 +471,10 @@ ExceptionOr<bool> ApplePaySession::canMakePayments(ScriptExecutionContext& scrip
 ExceptionOr<void> ApplePaySession::canMakePaymentsWithActiveCard(ScriptExecutionContext& scriptExecutionContext, const String& merchantIdentifier, Ref<DeferredPromise>&& passedPromise)
 {
     auto& document = downcast<Document>(scriptExecutionContext);
-    DOMWindow& window = *document.domWindow();
 
-    String errorMessage;
-    if (!canCallApplePaySessionAPIs(document, errorMessage)) {
-        window.printErrorMessage(errorMessage);
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    auto canCall = canCallApplePaySessionAPIs(document);
+    if (canCall.hasException())
+        return canCall.releaseException();
 
     RefPtr<DeferredPromise> promise(WTFMove(passedPromise));
     if (!shouldDiscloseApplePayCapability(document)) {
@@ -751,18 +498,13 @@ ExceptionOr<void> ApplePaySession::canMakePaymentsWithActiveCard(ScriptExecution
 ExceptionOr<void> ApplePaySession::openPaymentSetup(ScriptExecutionContext& scriptExecutionContext, const String& merchantIdentifier, Ref<DeferredPromise>&& passedPromise)
 {
     auto& document = downcast<Document>(scriptExecutionContext);
-    DOMWindow& window = *document.domWindow();
 
-    String errorMessage;
-    if (!canCallApplePaySessionAPIs(document, errorMessage)) {
-        window.printErrorMessage(errorMessage);
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    auto canCall = canCallApplePaySessionAPIs(document);
+    if (canCall.hasException())
+        return canCall.releaseException();
 
-    if (!ScriptController::processingUserGesture()) {
-        window.printErrorMessage("Must call ApplePaySession.openPaymentSetup from a user gesture handler.");
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    if (!ScriptController::processingUserGesture())
+        return Exception { INVALID_ACCESS_ERR, "Must call ApplePaySession.openPaymentSetup from a user gesture handler." };
 
     RefPtr<DeferredPromise> promise(WTFMove(passedPromise));
     auto& paymentCoordinator = document.frame()->mainFrame().paymentCoordinator();
@@ -776,27 +518,20 @@ ExceptionOr<void> ApplePaySession::openPaymentSetup(ScriptExecutionContext& scri
 
 ExceptionOr<void> ApplePaySession::begin()
 {
-    auto& document = *downcast<Document>(scriptExecutionContext());
-    auto& window = *document.domWindow();
+    if (!canBegin())
+        return Exception { INVALID_ACCESS_ERR, "Payment session is already active." };
 
-    if (!canBegin()) {
-        window.printErrorMessage("Payment session is already active.");
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    if (paymentCoordinator().hasActiveSession())
+        return Exception { INVALID_ACCESS_ERR, "Page already has an active payment session." };
 
-    if (paymentCoordinator().hasActiveSession()) {
-        window.printErrorMessage("Page already has an active payment session.");
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    auto& document = *downcast<Document>(scriptExecutionContext());
 
     Vector<URL> linkIconURLs;
     for (auto& icon : LinkIconCollector { document }.iconsOfTypes({ LinkIconType::TouchIcon, LinkIconType::TouchPrecomposedIcon }))
         linkIconURLs.append(icon.url);
 
-    if (!paymentCoordinator().beginPaymentSession(*this, document.url(), linkIconURLs, m_paymentRequest)) {
-        window.printErrorMessage("There is already has an active payment session.");
-        return Exception { INVALID_ACCESS_ERR };
-    }
+    if (!paymentCoordinator().beginPaymentSession(*this, document.url(), linkIconURLs, m_paymentRequest))
+        return Exception { INVALID_ACCESS_ERR, "There is already has an active payment session." };
 
     m_state = State::Active;
 
@@ -874,7 +609,7 @@ static std::optional<PaymentAuthorizationStatus> toPaymentAuthorizationStatus(un
     }
 }
 
-ExceptionOr<void> ApplePaySession::completeShippingMethodSelection(unsigned short status, const Dictionary& newTotalDictionary, const ArrayValue& newLineItemsArray)
+ExceptionOr<void> ApplePaySession::completeShippingMethodSelection(unsigned short status, LineItem&& newTotal, Vector<LineItem>&& newLineItems)
 {
     if (!canCompleteShippingMethodSelection())
         return Exception { INVALID_ACCESS_ERR };
@@ -883,28 +618,31 @@ ExceptionOr<void> ApplePaySession::completeShippingMethodSelection(unsigned shor
     if (!authorizationStatus)
         return Exception { INVALID_ACCESS_ERR };
 
-    auto& window = *downcast<Document>(scriptExecutionContext())->domWindow();
-    auto newTotal = createLineItem(window, newTotalDictionary);
-    if (!newTotal)
-        return Exception { INVALID_ACCESS_ERR };
+    auto convertedNewTotal = convertAndValidate(WTFMove(newTotal));
+    if (convertedNewTotal.hasException())
+        return convertedNewTotal.releaseException();
 
-    if (!PaymentRequestValidator(window).validateTotal(*newTotal))
-        return Exception { INVALID_ACCESS_ERR };
+    WebCore::PaymentRequest::TotalAndLineItems totalAndLineItems;
+    totalAndLineItems.total = convertedNewTotal.releaseReturnValue();
 
-    auto newLineItems = createLineItems(window, newLineItemsArray);
-    if (!newLineItems)
-        return Exception { INVALID_ACCESS_ERR };
+    // FIXME: Merge this validation into the validation we are doing above.
+    auto validatedTotal = PaymentRequestValidator::validateTotal(totalAndLineItems.total);
+    if (validatedTotal.hasException())
+        return validatedTotal.releaseException();
+
+    auto convertedNewLineItems = convertAndValidate(WTFMove(newLineItems));
+    if (convertedNewLineItems.hasException())
+        return convertedNewLineItems.releaseException();
+
+    totalAndLineItems.lineItems = convertedNewLineItems.releaseReturnValue();
 
     m_state = State::Active;
-    PaymentRequest::TotalAndLineItems totalAndLineItems;
-    totalAndLineItems.total = *newTotal;
-    totalAndLineItems.lineItems = *newLineItems;
     paymentCoordinator().completeShippingMethodSelection(*authorizationStatus, totalAndLineItems);
 
     return { };
 }
 
-ExceptionOr<void> ApplePaySession::completeShippingContactSelection(unsigned short status, const ArrayValue& newShippingMethodsArray, const Dictionary& newTotalDictionary, const ArrayValue& newLineItemsArray)
+ExceptionOr<void> ApplePaySession::completeShippingContactSelection(unsigned short status, Vector<ShippingMethod>&& newShippingMethods, LineItem&& newTotal, Vector<LineItem>&& newLineItems)
 {
     if (!canCompleteShippingContactSelection())
         return Exception { INVALID_ACCESS_ERR };
@@ -913,53 +651,58 @@ ExceptionOr<void> ApplePaySession::completeShippingContactSelection(unsigned sho
     if (!authorizationStatus)
         return Exception { INVALID_ACCESS_ERR };
 
-    auto& window = *downcast<Document>(scriptExecutionContext())->domWindow();
+    auto convertedNewShippingMethods = convertAndValidate(WTFMove(newShippingMethods));
+    if (convertedNewShippingMethods.hasException())
+        return convertedNewShippingMethods.releaseException();
 
-    auto newShippingMethods = createShippingMethods(window, newShippingMethodsArray);
-    if (!newShippingMethods)
-        return Exception { INVALID_ACCESS_ERR };
+    auto convertedNewTotal = convertAndValidate(WTFMove(newTotal));
+    if (convertedNewTotal.hasException())
+        return convertedNewTotal.releaseException();
 
-    auto newTotal = createLineItem(window, newTotalDictionary);
-    if (!newTotal)
-        return Exception { INVALID_ACCESS_ERR };
+    WebCore::PaymentRequest::TotalAndLineItems totalAndLineItems;
+    totalAndLineItems.total = convertedNewTotal.releaseReturnValue();
 
-    if (!PaymentRequestValidator(window).validateTotal(*newTotal))
-        return Exception { INVALID_ACCESS_ERR };
+    // FIXME: Merge this validation into the validation we are doing above.
+    auto validatedTotal = PaymentRequestValidator::validateTotal(totalAndLineItems.total);
+    if (validatedTotal.hasException())
+        return validatedTotal.releaseException();
 
-    auto newLineItems = createLineItems(window, newLineItemsArray);
-    if (!newLineItems)
-        return Exception { INVALID_ACCESS_ERR };
+    auto convertedNewLineItems = convertAndValidate(WTFMove(newLineItems));
+    if (convertedNewLineItems.hasException())
+        return convertedNewLineItems.releaseException();
+
+    totalAndLineItems.lineItems = convertedNewLineItems.releaseReturnValue();
 
     m_state = State::Active;
-    PaymentRequest::TotalAndLineItems totalAndLineItems;
-    totalAndLineItems.total = *newTotal;
-    totalAndLineItems.lineItems = *newLineItems;
-    paymentCoordinator().completeShippingContactSelection(*authorizationStatus, *newShippingMethods, totalAndLineItems);
+    paymentCoordinator().completeShippingContactSelection(*authorizationStatus, convertedNewShippingMethods.releaseReturnValue(), totalAndLineItems);
 
     return { };
 }
 
-ExceptionOr<void> ApplePaySession::completePaymentMethodSelection(const Dictionary& newTotalDictionary, const ArrayValue& newLineItemsArray)
+ExceptionOr<void> ApplePaySession::completePaymentMethodSelection(LineItem&& newTotal, Vector<LineItem>&& newLineItems)
 {
     if (!canCompletePaymentMethodSelection())
         return Exception { INVALID_ACCESS_ERR };
 
-    auto& window = *downcast<Document>(*scriptExecutionContext()).domWindow();
-    auto newTotal = createLineItem(window, newTotalDictionary);
-    if (!newTotal)
-        return Exception { INVALID_ACCESS_ERR };
+    auto convertedNewTotal = convertAndValidate(WTFMove(newTotal));
+    if (convertedNewTotal.hasException())
+        return convertedNewTotal.releaseException();
 
-    if (!PaymentRequestValidator(window).validateTotal(*newTotal))
-        return Exception { INVALID_ACCESS_ERR };
+    WebCore::PaymentRequest::TotalAndLineItems totalAndLineItems;
+    totalAndLineItems.total = convertedNewTotal.releaseReturnValue();
 
-    auto newLineItems = createLineItems(window, newLineItemsArray);
-    if (!newLineItems)
-        return Exception { INVALID_ACCESS_ERR };
+    // FIXME: Merge this validation into the validation we are doing above.
+    auto validatedTotal = PaymentRequestValidator::validateTotal(totalAndLineItems.total);
+    if (validatedTotal.hasException())
+        return validatedTotal.releaseException();
+
+    auto convertedNewLineItems = convertAndValidate(WTFMove(newLineItems));
+    if (convertedNewLineItems.hasException())
+        return convertedNewLineItems.releaseException();
+
+    totalAndLineItems.lineItems = convertedNewLineItems.releaseReturnValue();
 
     m_state = State::Active;
-    PaymentRequest::TotalAndLineItems totalAndLineItems;
-    totalAndLineItems.total = *newTotal;
-    totalAndLineItems.lineItems = *newLineItems;
     paymentCoordinator().completePaymentMethodSelection(totalAndLineItems);
 
     return { };
@@ -1018,7 +761,7 @@ void ApplePaySession::didAuthorizePayment(const Payment& payment)
     dispatchEvent(event.get());
 }
 
-void ApplePaySession::didSelectShippingMethod(const PaymentRequest::ShippingMethod& shippingMethod)
+void ApplePaySession::didSelectShippingMethod(const WebCore::PaymentRequest::ShippingMethod& shippingMethod)
 {
     ASSERT(m_state == State::Active);
 
index 475dffa..5252fa8 100644 (file)
 #include "EventTarget.h"
 #include "ExceptionOr.h"
 #include "PaymentRequest.h"
+#include <heap/Strong.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
 
 namespace WebCore {
 
-class ArrayValue;
 class DeferredPromise;
-class Dictionary;
 class Document;
 class Payment;
 class PaymentContact;
@@ -48,7 +47,47 @@ class URL;
 
 class ApplePaySession final : public RefCounted<ApplePaySession>, public ActiveDOMObject, public EventTargetWithInlineData {
 public:
-    static ExceptionOr<Ref<ApplePaySession>> create(JSC::ExecState&, Document&, unsigned version, JSC::JSValue);
+    enum class MerchantCapability { Supports3DS, SupportsEMV, SupportsCredit, SupportsDebit };
+    enum class ContactField { Email, Name, Phone, PostalAddress };
+
+    using ShippingType = WebCore::PaymentRequest::ShippingType;
+    using LineItemType = WebCore::PaymentRequest::LineItem::Type;
+
+    struct ShippingMethod {
+        String label;
+        String detail;
+        String amount;
+        String identifier;
+    };
+
+    struct LineItem {
+        LineItemType type { LineItemType::Final };
+        String label;
+        String amount;
+    };
+
+    struct PaymentRequest {
+        Vector<MerchantCapability> merchantCapabilities;
+        Vector<String> supportedNetworks;
+        String countryCode;
+        String currencyCode;
+
+        std::optional<Vector<ContactField>> requiredBillingContactFields;
+        JSC::Strong<JSC::JSObject> billingContact;
+
+        std::optional<Vector<ContactField>>  requiredShippingContactFields;
+        JSC::Strong<JSC::JSObject> shippingContact;
+
+        ShippingType shippingType { ShippingType::Shipping };
+        std::optional<Vector<ShippingMethod>> shippingMethods;
+
+        LineItem total;
+        Vector<LineItem> lineItems;
+
+        String applicationData;
+    };
+
+    static ExceptionOr<Ref<ApplePaySession>> create(JSC::ExecState&, Document&, unsigned version, PaymentRequest&&);
     virtual ~ApplePaySession();
 
     // DOM API.
@@ -68,17 +107,17 @@ public:
 
     ExceptionOr<void> begin();
     ExceptionOr<void> abort();
-    ExceptionOr<void> completeMerchantValidation(JSC::ExecState&, JSC::JSValue merchantSessionDictionary);
-    ExceptionOr<void> completeShippingMethodSelection(unsigned short status, const Dictionary& newTotal, const ArrayValue& newLineItems);
-    ExceptionOr<void> completeShippingContactSelection(unsigned short status, const ArrayValue& newShippingMethods, const Dictionary& newTotal, const ArrayValue& newLineItems);
-    ExceptionOr<void> completePaymentMethodSelection(const Dictionary& newTotal, const ArrayValue& newLineItems);
+    ExceptionOr<void> completeMerchantValidation(JSC::ExecState&, JSC::JSValue merchantSession);
+    ExceptionOr<void> completeShippingMethodSelection(unsigned short status, LineItem&& newTotal, Vector<LineItem>&& newLineItems);
+    ExceptionOr<void> completeShippingContactSelection(unsigned short status, Vector<ShippingMethod>&& newShippingMethods, LineItem&& newTotal, Vector<LineItem>&& newLineItems);
+    ExceptionOr<void> completePaymentMethodSelection(LineItem&& newTotal, Vector<LineItem>&& newLineItems);
     ExceptionOr<void> completePayment(unsigned short status);
 
-    const PaymentRequest& paymentRequest() const { return m_paymentRequest; }
+    const WebCore::PaymentRequest& paymentRequest() const { return m_paymentRequest; }
 
     void validateMerchant(const URL&);
     void didAuthorizePayment(const Payment&);
-    void didSelectShippingMethod(const PaymentRequest::ShippingMethod&);
+    void didSelectShippingMethod(const WebCore::PaymentRequest::ShippingMethod&);
     void didSelectShippingContact(const PaymentContact&);
     void didSelectPaymentMethod(const PaymentMethod&);
     void didCancelPayment();
@@ -87,7 +126,7 @@ public:
     using RefCounted<ApplePaySession>::deref;
 
 private:
-    ApplePaySession(Document&, PaymentRequest&&);
+    ApplePaySession(Document&, WebCore::PaymentRequest&&);
 
     // ActiveDOMObject.
     const char* activeDOMObjectName() const override;
@@ -134,7 +173,7 @@ private:
         ValidationComplete,
     } m_merchantValidationState { MerchantValidationState::Idle };
 
-    const PaymentRequest m_paymentRequest;
+    const WebCore::PaymentRequest m_paymentRequest;
 };
 
 }
index 53ad680..ca2fbf2 100644 (file)
@@ -26,8 +26,8 @@
 [
     ActiveDOMObject,
     Conditional=APPLE_PAY,
-    Constructor(unsigned long version, any paymentRequest),
-    ConstructorCallWith=Document&ScriptState,
+    Constructor(unsigned long version, ApplePayPaymentRequest paymentRequest),
+    ConstructorCallWith=ScriptState&Document,
     ConstructorMayThrowException,
     EnabledBySetting=ApplePay,
 ] interface ApplePaySession : EventTarget {
 
     [MayThrowException] void begin();
     [MayThrowException] void abort();
-    [CallWith=ScriptState, MayThrowException] void completeMerchantValidation(any merchantSession);
-    [Custom, MayThrowException] void completeShippingMethodSelection(unsigned short status, any newTotal, any newLineItems);
-    [Custom, MayThrowException] void completeShippingContactSelection(unsigned short status, any newShippingMethods, any newTotal, any newLineItems);
-    [Custom, MayThrowException] void completePaymentMethodSelection(any newTotal, any newLineItems);
+    [MayThrowException, CallWith=ScriptState] void completeMerchantValidation(any merchantSession);
+    [MayThrowException] void completeShippingMethodSelection(unsigned short status, ApplePayLineItem newTotal, sequence<ApplePayLineItem> newLineItems);
+    [MayThrowException] void completeShippingContactSelection(unsigned short status, sequence<ApplePayShippingMethod> newShippingMethods, ApplePayLineItem newTotal, sequence<ApplePayLineItem> newLineItems);
+    [MayThrowException] void completePaymentMethodSelection(ApplePayLineItem newTotal, sequence<ApplePayLineItem> newLineItems);
     [MayThrowException] void completePayment(unsigned short status);
 
     attribute EventHandler onvalidatemerchant;
     attribute EventHandler onshippingcontactselected;
     attribute EventHandler oncancel;
 };
+
+enum ApplePayMerchantCapability {
+    "supports3DS",
+    "supportsEMV",
+    "supportsCredit",
+    "supportsDebit"
+};
+
+enum ApplePayContactField {
+    "email",
+    "name",
+    "phone",
+    "postalAddress"
+};
+
+enum ApplePayShippingType {
+    "shipping",
+    "delivery",
+    "storePickup",
+    "servicePickup"
+};
+
+dictionary ApplePayShippingMethod {
+    required DOMString label;
+    required DOMString detail;
+    required DOMString amount;
+    required DOMString identifier;
+};
+
+enum ApplePayLineItemType {
+    "pending",
+    "final"
+};
+
+dictionary ApplePayLineItem {
+    ApplePayLineItemType type = "final";
+    DOMString label;
+    DOMString amount;
+};
+
+dictionary ApplePayPaymentRequest {
+    required ApplePayLineItem total;
+    sequence<ApplePayLineItem> lineItems;
+
+    required sequence<ApplePayMerchantCapability> merchantCapabilities;
+    required sequence<DOMString> supportedNetworks; // FIXME: Should this be an sequence of enums?
+    required DOMString countryCode;
+    required DOMString currencyCode;
+
+    sequence<ApplePayContactField> requiredBillingContactFields;
+    object billingContact;
+
+    sequence<ApplePayContactField> requiredShippingContactFields;
+    object shippingContact;
+
+    ApplePayShippingType shippingType = "shipping";
+    sequence<ApplePayShippingMethod> shippingMethods;
+
+    DOMString applicationData;
+};
index b435b6b..9245841 100644 (file)
 
 #if ENABLE(APPLE_PAY)
 
-#include "DOMWindow.h"
-#include "PageConsoleClient.h"
+#include "ExceptionCode.h"
 #include "PaymentRequest.h"
 #include <unicode/ucurr.h>
 #include <unicode/uloc.h>
 
 namespace WebCore {
 
-PaymentRequestValidator::PaymentRequestValidator(DOMWindow& window)
-    : m_window(window)
-{
-}
+static ExceptionOr<void> validateCountryCode(const String&);
+static ExceptionOr<void> validateCurrencyCode(const String&);
+static ExceptionOr<void> validateMerchantCapabilities(const PaymentRequest::MerchantCapabilities&);
+static ExceptionOr<void> validateSupportedNetworks(const Vector<String>&);
+static ExceptionOr<void> validateShippingMethods(const Vector<PaymentRequest::ShippingMethod>&);
+static ExceptionOr<void> validateShippingMethod(const PaymentRequest::ShippingMethod&);
 
-PaymentRequestValidator::~PaymentRequestValidator()
-{
-}
 
-bool PaymentRequestValidator::validate(const PaymentRequest& paymentRequest) const
+ExceptionOr<void> PaymentRequestValidator::validate(const PaymentRequest& paymentRequest)
 {
-    if (!validateCountryCode(paymentRequest.countryCode()))
-        return false;
-    if (!validateCurrencyCode(paymentRequest.currencyCode()))
-        return false;
-    if (!validateSupportedNetworks(paymentRequest.supportedNetworks()))
-        return false;
-    if (!validateMerchantCapabilities(paymentRequest.merchantCapabilities()))
-        return false;
-    if (!validateTotal(paymentRequest.total()))
-        return false;
-    if (!validateShippingMethods(paymentRequest.shippingMethods()))
-        return false;
-    return true;
+    auto validatedCountryCode = validateCountryCode(paymentRequest.countryCode());
+    if (validatedCountryCode.hasException())
+        return validatedCountryCode.releaseException();
+
+    auto validatedCurrencyCode = validateCurrencyCode(paymentRequest.currencyCode());
+    if (validatedCurrencyCode.hasException())
+        return validatedCurrencyCode.releaseException();
+
+    auto validatedSupportedNetworks = validateSupportedNetworks(paymentRequest.supportedNetworks());
+    if (validatedSupportedNetworks.hasException())
+        return validatedSupportedNetworks.releaseException();
+
+    auto validatedMerchantCapabilities = validateMerchantCapabilities(paymentRequest.merchantCapabilities());
+    if (validatedMerchantCapabilities.hasException())
+        return validatedMerchantCapabilities.releaseException();
+
+    auto validatedTotal = validateTotal(paymentRequest.total());
+    if (validatedTotal.hasException())
+        return validatedTotal.releaseException();
+
+    auto validatedShippingMethods = validateShippingMethods(paymentRequest.shippingMethods());
+    if (validatedShippingMethods.hasException())
+        return validatedShippingMethods.releaseException();
+
+    return { };
 }
 
-bool PaymentRequestValidator::validateTotal(const PaymentRequest::LineItem& total) const
+ExceptionOr<void> PaymentRequestValidator::validateTotal(const PaymentRequest::LineItem& total)
 {
-    if (!total.label) {
-        m_window.printErrorMessage("Missing total label.");
-        return false;
-    }
+    if (!total.label)
+        return Exception { TypeError, "Missing total label." };
 
-    if (!total.amount) {
-        m_window.printErrorMessage("Missing total amount.");
-        return false;
-    }
+    if (!total.amount)
+        return Exception { TypeError, "Missing total amount." };
 
-    if (*total.amount <= 0) {
-        m_window.printErrorMessage("Total amount must be greater than zero.");
-        return false;
-    }
+    if (*total.amount <= 0) 
+        return Exception { TypeError, "Total amount must be greater than zero." };
 
-    if (*total.amount > 10000000000) {
-        m_window.printErrorMessage("Total amount is too big.");
-        return false;
-    }
+    if (*total.amount > 10000000000)
+        return Exception { TypeError, "Total amount is too big." };
 
-    return true;
+    return { };
 }
 
-bool PaymentRequestValidator::validateCountryCode(const String& countryCode) const
+static ExceptionOr<void> validateCountryCode(const String& countryCode)
 {
-    if (!countryCode) {
-        m_window.printErrorMessage("Missing country code.");
-        return false;
-    }
+    if (!countryCode)
+        return Exception { TypeError, "Missing country code." };
 
     for (auto *countryCodePtr = uloc_getISOCountries(); *countryCodePtr; ++countryCodePtr) {
         if (countryCode == *countryCodePtr)
-            return true;
+            return { };
     }
 
-    auto message = makeString("\"" + countryCode, "\" is not a valid country code.");
-    m_window.printErrorMessage(message);
-
-    return false;
+    return Exception { TypeError, makeString("\"" + countryCode, "\" is not a valid country code.") };
 }
 
-bool PaymentRequestValidator::validateCurrencyCode(const String& currencyCode) const
+static ExceptionOr<void> validateCurrencyCode(const String& currencyCode)
 {
-    if (!currencyCode) {
-        m_window.printErrorMessage("Missing currency code.");
-        return false;
-    }
+    if (!currencyCode)
+        return Exception { TypeError, "Missing currency code." };
 
     UErrorCode errorCode = U_ZERO_ERROR;
     auto currencyCodes = std::unique_ptr<UEnumeration, void (*)(UEnumeration*)>(ucurr_openISOCurrencies(UCURR_ALL, &errorCode), uenum_close);
@@ -118,53 +113,45 @@ bool PaymentRequestValidator::validateCurrencyCode(const String& currencyCode) c
     int32_t length;
     while (auto *currencyCodePtr = uenum_next(currencyCodes.get(), &length, &errorCode)) {
         if (currencyCodePtr == currencyCode)
-            return true;
+            return { };
     }
 
-    auto message = makeString("\"" + currencyCode, "\" is not a valid currency code.");
-    m_window.printErrorMessage(message);
-
-    return false;
+    return Exception { TypeError, makeString("\"" + currencyCode, "\" is not a valid currency code.") };
 }
 
-bool PaymentRequestValidator::validateMerchantCapabilities(const PaymentRequest::MerchantCapabilities& merchantCapabilities) const
+static ExceptionOr<void> validateMerchantCapabilities(const PaymentRequest::MerchantCapabilities& merchantCapabilities)
 {
-    if (!merchantCapabilities.supports3DS && !merchantCapabilities.supportsEMV && !merchantCapabilities.supportsCredit && !merchantCapabilities.supportsDebit) {
-        m_window.printErrorMessage("Missing merchant capabilities");
-        return false;
-    }
+    if (!merchantCapabilities.supports3DS && !merchantCapabilities.supportsEMV && !merchantCapabilities.supportsCredit && !merchantCapabilities.supportsDebit)
+        return Exception { TypeError, "Missing merchant capabilities." };
 
-    return true;
+    return { };
 }
 
-bool PaymentRequestValidator::validateShippingMethod(const PaymentRequest::ShippingMethod& shippingMethod) const
+static ExceptionOr<void> validateSupportedNetworks(const Vector<String>& supportedNetworks)
 {
-    if (shippingMethod.amount < 0) {
-        m_window.printErrorMessage("Shipping method amount must be greater than or equal to zero.");
-        return false;
-    }
+    if (supportedNetworks.isEmpty())
+        return Exception { TypeError, "Missing supported networks." };
 
-    return true;
+    return { };
 }
 
-bool PaymentRequestValidator::validateSupportedNetworks(const Vector<String>& supportedNetworks) const
+static ExceptionOr<void> validateShippingMethod(const PaymentRequest::ShippingMethod& shippingMethod)
 {
-    if (supportedNetworks.isEmpty()) {
-        m_window.printErrorMessage("Missing supported networks");
-        return false;
-    }
+    if (shippingMethod.amount < 0)
+        return Exception { TypeError, "Shipping method amount must be greater than or equal to zero." };
 
-    return true;
+    return { };
 }
 
-bool PaymentRequestValidator::validateShippingMethods(const Vector<PaymentRequest::ShippingMethod>& shippingMethods) const
+static ExceptionOr<void> validateShippingMethods(const Vector<PaymentRequest::ShippingMethod>& shippingMethods)
 {
     for (const auto& shippingMethod : shippingMethods) {
-        if (!validateShippingMethod(shippingMethod))
-            return false;
+        auto validatedShippingMethod = validateShippingMethod(shippingMethod);
+        if (validatedShippingMethod.hasException())
+            return validatedShippingMethod.releaseException();
     }
 
-    return true;
+    return { };
 }
 
 }
index d24bddb..bcd6185 100644 (file)
 
 #if ENABLE(APPLE_PAY)
 
+#include "ExceptionOr.h"
 #include "PaymentRequest.h"
 
 namespace WebCore {
 
-class DOMWindow;
-
 class PaymentRequestValidator {
 public:
-    explicit PaymentRequestValidator(DOMWindow&);
-    ~PaymentRequestValidator();
-
-    bool validate(const PaymentRequest&) const;
-    bool validateTotal(const PaymentRequest::LineItem&) const;
-
-private:
-    bool validateCountryCode(const String&) const;
-    bool validateCurrencyCode(const String&) const;
-    bool validateMerchantCapabilities(const PaymentRequest::MerchantCapabilities&) const;
-    bool validateSupportedNetworks(const Vector<String>&) const;
-
-    bool validateShippingMethods(const Vector<PaymentRequest::ShippingMethod>&) const;
-    bool validateShippingMethod(const PaymentRequest::ShippingMethod&) const;
-
-    DOMWindow& m_window;
+    static ExceptionOr<void> validate(const PaymentRequest&);
+    static ExceptionOr<void> validateTotal(const PaymentRequest::LineItem&);
 };
 
 }
index c190c3b..61a6018 100644 (file)
                1AE96A951D1A0DDD00B86768 /* JSApplePayValidateMerchantEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AE96A851D1A0A8000B86768 /* JSApplePayValidateMerchantEvent.h */; };
                1AE96A961D1A100700B86768 /* JSApplePayPaymentAuthorizedEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE96A741D1A04D300B86768 /* JSApplePayPaymentAuthorizedEventCustom.cpp */; };
                1AE96A971D1A100700B86768 /* JSApplePayPaymentMethodSelectedEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE96A751D1A04D300B86768 /* JSApplePayPaymentMethodSelectedEventCustom.cpp */; };
-               1AE96A981D1A100700B86768 /* JSApplePaySessionCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE96A761D1A04D300B86768 /* JSApplePaySessionCustom.cpp */; };
                1AE96A991D1A100700B86768 /* JSApplePayShippingContactSelectedEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE96A771D1A04D300B86768 /* JSApplePayShippingContactSelectedEventCustom.cpp */; };
                1AE96A9A1D1A100700B86768 /* JSApplePayShippingMethodSelectedEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE96A781D1A04D300B86768 /* JSApplePayShippingMethodSelectedEventCustom.cpp */; };
                1AED3BDA1D3D5F260099FD78 /* PassKitSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AED3BD91D3D5F260099FD78 /* PassKitSPI.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1AE82FEB0CAB07EE002237AE /* JSSQLResultSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSQLResultSet.h; sourceTree = "<group>"; };
                1AE96A741D1A04D300B86768 /* JSApplePayPaymentAuthorizedEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayPaymentAuthorizedEventCustom.cpp; sourceTree = "<group>"; };
                1AE96A751D1A04D300B86768 /* JSApplePayPaymentMethodSelectedEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayPaymentMethodSelectedEventCustom.cpp; sourceTree = "<group>"; };
-               1AE96A761D1A04D300B86768 /* JSApplePaySessionCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePaySessionCustom.cpp; sourceTree = "<group>"; };
                1AE96A771D1A04D300B86768 /* JSApplePayShippingContactSelectedEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayShippingContactSelectedEventCustom.cpp; sourceTree = "<group>"; };
                1AE96A781D1A04D300B86768 /* JSApplePayShippingMethodSelectedEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayShippingMethodSelectedEventCustom.cpp; sourceTree = "<group>"; };
                1AE96A7A1D1A0A8000B86768 /* JSApplePayPaymentAuthorizedEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayPaymentAuthorizedEvent.cpp; sourceTree = "<group>"; };
                                1221E0721C03E4C2006A1A00 /* JSAnimationTimelineCustom.cpp */,
                                1AE96A741D1A04D300B86768 /* JSApplePayPaymentAuthorizedEventCustom.cpp */,
                                1AE96A751D1A04D300B86768 /* JSApplePayPaymentMethodSelectedEventCustom.cpp */,
-                               1AE96A761D1A04D300B86768 /* JSApplePaySessionCustom.cpp */,
                                1AE96A771D1A04D300B86768 /* JSApplePayShippingContactSelectedEventCustom.cpp */,
                                1AE96A781D1A04D300B86768 /* JSApplePayShippingMethodSelectedEventCustom.cpp */,
                                BC2ED6BB0C6BD2F000920BFF /* JSAttrCustom.cpp */,
                                1AE96A8C1D1A0DDD00B86768 /* JSApplePayPaymentMethodSelectedEvent.cpp in Sources */,
                                1AE96A971D1A100700B86768 /* JSApplePayPaymentMethodSelectedEventCustom.cpp in Sources */,
                                1AE96A8E1D1A0DDD00B86768 /* JSApplePaySession.cpp in Sources */,
-                               1AE96A981D1A100700B86768 /* JSApplePaySessionCustom.cpp in Sources */,
                                1AE96A901D1A0DDD00B86768 /* JSApplePayShippingContactSelectedEvent.cpp in Sources */,
                                1AE96A991D1A100700B86768 /* JSApplePayShippingContactSelectedEventCustom.cpp in Sources */,
                                1AE96A921D1A0DDD00B86768 /* JSApplePayShippingMethodSelectedEvent.cpp in Sources */,
index 6010a6f..4ebbcf7 100644 (file)
@@ -95,7 +95,13 @@ struct IDLDOMString : IDLString { };
 struct IDLByteString : IDLString { };
 struct IDLUSVString : IDLString { };
 
-struct IDLObject : IDLType<JSC::Strong<JSC::JSObject>> { };
+struct IDLObject : IDLType<JSC::Strong<JSC::JSObject>> {
+    using NullableType = JSC::Strong<JSC::JSObject>;
+
+    static inline std::nullptr_t nullValue() { return nullptr; }
+    template<typename U> static inline bool isNullValue(U&& value) { return !value; }
+    template<typename U> static inline U&& extractValueFromNullable(U&& value) { return std::forward<U>(value); }
+};
 
 template<typename T> struct IDLWrapper : IDLType<RefPtr<T>> {
     using RawType = T;
diff --git a/Source/WebCore/bindings/js/JSApplePaySessionCustom.cpp b/Source/WebCore/bindings/js/JSApplePaySessionCustom.cpp
deleted file mode 100644 (file)
index cf3781d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "JSApplePaySession.h"
-
-#if ENABLE(APPLE_PAY)
-
-#include "ArrayValue.h"
-#include "Dictionary.h"
-#include "JSDOMBinding.h"
-#include "JSDOMConvert.h"
-#include <runtime/Error.h>
-
-using namespace JSC;
-
-namespace WebCore {
-
-JSValue JSApplePaySession::completeShippingMethodSelection(ExecState& state)
-{
-    VM& vm = state.vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    JSValue thisValue = state.thisValue();
-    JSApplePaySession* castedThis = jsDynamicDowncast<JSApplePaySession*>(thisValue);
-    if (UNLIKELY(!castedThis))
-        return JSValue::decode(throwThisTypeError(state, scope, "ApplePaySession", "completeShippingMethodSelection"));
-
-    ASSERT_GC_OBJECT_INHERITS(castedThis, JSApplePaySession::info());
-    auto& impl = castedThis->wrapped();
-    if (UNLIKELY(state.argumentCount() < 3))
-        return JSValue::decode(throwVMError(&state, scope, createNotEnoughArgumentsError(&state)));
-
-    uint16_t status = convert<IDLUnsignedShort>(state, state.uncheckedArgument(0), IntegerConversionConfiguration::Normal);
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    Dictionary newTotal = { &state, state.uncheckedArgument(1) };
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    ArrayValue newLineItems { &state, state.uncheckedArgument(2) };
-    RETURN_IF_EXCEPTION(scope, JSValue());
-    propagateException(state, scope, impl.completeShippingMethodSelection(status, newTotal, newLineItems));
-
-    return jsUndefined();
-}
-
-JSValue JSApplePaySession::completeShippingContactSelection(ExecState& state)
-{
-    VM& vm = state.vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    JSValue thisValue = state.thisValue();
-    JSApplePaySession* castedThis = jsDynamicDowncast<JSApplePaySession*>(thisValue);
-    if (UNLIKELY(!castedThis))
-        return JSValue::decode(throwThisTypeError(state, scope, "ApplePaySession", "completeShippingContactSelection"));
-
-    ASSERT_GC_OBJECT_INHERITS(castedThis, JSApplePaySession::info());
-    auto& impl = castedThis->wrapped();
-    if (UNLIKELY(state.argumentCount() < 4))
-        return JSValue::decode(throwVMError(&state, scope, createNotEnoughArgumentsError(&state)));
-
-    uint16_t status = convert<IDLUnsignedShort>(state, state.uncheckedArgument(0), IntegerConversionConfiguration::Normal);
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    ArrayValue newShippingMethods { &state, state.uncheckedArgument(1) };
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    Dictionary newTotal = { &state, state.uncheckedArgument(2) };
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    ArrayValue newLineItems { &state, state.uncheckedArgument(3) };
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    propagateException(state, scope, impl.completeShippingContactSelection(status, newShippingMethods, newTotal, newLineItems));
-
-    return jsUndefined();
-}
-
-JSValue JSApplePaySession::completePaymentMethodSelection(ExecState& state)
-{
-    VM& vm = state.vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    JSValue thisValue = state.thisValue();
-    JSApplePaySession* castedThis = jsDynamicDowncast<JSApplePaySession*>(thisValue);
-    if (UNLIKELY(!castedThis))
-        return JSValue::decode(throwThisTypeError(state, scope, "ApplePaySession", "completePaymentMethodSelection"));
-
-    ASSERT_GC_OBJECT_INHERITS(castedThis, JSApplePaySession::info());
-    auto& impl = castedThis->wrapped();
-    if (UNLIKELY(state.argumentCount() < 2))
-        return JSValue::decode(throwVMError(&state, scope, createNotEnoughArgumentsError(&state)));
-
-    Dictionary newTotal = { &state, state.uncheckedArgument(0) };
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    ArrayValue newLineItems { &state, state.uncheckedArgument(1) };
-    RETURN_IF_EXCEPTION(scope, JSValue());
-
-    propagateException(state, scope, impl.completePaymentMethodSelection(newTotal, newLineItems));
-
-    return jsUndefined();
-}
-
-}
-
-#endif
index 38e205e..1a89493 100644 (file)
@@ -1,3 +1,15 @@
+2016-12-12  Sam Weinig  <sam@webkit.org>
+
+        [WebIDL] Remove use of Dictionary in ApplePaySession
+        https://bugs.webkit.org/show_bug.cgi?id=165787
+
+        Reviewed by Anders Carlsson.
+
+        * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+        (WTR::initializeWebViewConfiguration):
+        (WTR::TestController::platformCreateWebView):
+        Enable ApplePay for the tests (where supported).
+
 2016-12-13  Eric Carlson  <eric.carlson@apple.com>
 
         Annotate MediaStream and WebRTC idl with EnabledAtRuntime flag
index aace482..84f971a 100644 (file)
@@ -59,7 +59,11 @@ void initializeWebViewConfiguration(const char* libraryPath, WKStringRef injecte
     globalWebViewConfiguration.websiteDataStore = (WKWebsiteDataStore *)WKContextGetWebsiteDataStore(context);
     globalWebViewConfiguration._allowUniversalAccessFromFileURLs = YES;
 
-#if TARGET_OS_IPHONE
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
+    globalWebViewConfiguration._applePayEnabled = YES;
+#endif
+
+#if PLATFORM(IOS)
     globalWebViewConfiguration.allowsInlineMediaPlayback = YES;
     globalWebViewConfiguration._inlineMediaPlaybackRequiresPlaysInlineAttribute = NO;
     globalWebViewConfiguration._invisibleAutoplayNotPermitted = NO;
@@ -83,7 +87,8 @@ void TestController::platformCreateWebView(WKPageConfigurationRef, const TestOpt
 {
 #if WK_API_ENABLED
     RetainPtr<WKWebViewConfiguration> copiedConfiguration = adoptNS([globalWebViewConfiguration copy]);
-#if TARGET_OS_IPHONE
+
+#if PLATFORM(IOS)
     if (options.useDataDetection)
         [copiedConfiguration setDataDetectorTypes:WKDataDetectorTypeAll];
     if (options.ignoresViewportScaleLimits)