[Payment Request] Perform payment method data IDL conversion in the PaymentRequest...
authoraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 3 Jan 2020 01:05:28 +0000 (01:05 +0000)
committeraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 3 Jan 2020 01:05:28 +0000 (01:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=199225
<rdar://problem/52217847>

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Imported test web-platform-tests/payment-request/constructor_convert_method_data.https.html
using Tools/Scripts/import-w3c-tests.

* web-platform-tests/payment-request/constructor_convert_method_data.https-expected.txt: Added.
* web-platform-tests/payment-request/constructor_convert_method_data.https.html: Added.
* web-platform-tests/payment-request/w3c-import.log:

Source/WebCore:

Implemented support for validating payment method data during Payment Request construction.
IDL conversion errors for payment method data will now trigger an exception in the
PaymentRequest constructor rather than being deferred to the show() method.

Payment Request specified this change in <https://github.com/w3c/payment-request/pull/829>.

Test: imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https.html

* Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp:
(WebCore::convertAndValidate): Moved the logic for converting a JSValue to an
ApplePayRequest IDL type from ApplePayPaymentHandler::convertData to here.
(WebCore::ApplePayPaymentHandler::validateData): Added. Checks that the specified JSValue is
a valid ApplePayRequest, throwing an exception if not.
(WebCore::ApplePayPaymentHandler::convertData): Changed to use convertAndValidate to convert
from a JSValue to an ApplePayRequest.
* Modules/applepay/paymentrequest/ApplePayPaymentHandler.h:
* Modules/paymentrequest/PaymentHandler.cpp:
(WebCore::PaymentHandler::validateData): Added. Calls ApplePayPaymentHandler::validateData
if Apple Pay handles the specified identifier.
* Modules/paymentrequest/PaymentHandler.h:
* Modules/paymentrequest/PaymentRequest.cpp:
(WebCore::parse): Moved up to be callable by PaymentRequest::create.
(WebCore::PaymentRequest::create): Validated that serializedData can be converted to a valid
ApplePayRequest, throwing an exception if not.

LayoutTests:

* http/tests/ssl/applepay/PaymentRequest.https-expected.txt:
* http/tests/ssl/applepay/PaymentRequest.https.html: Changed some tests to expect exceptions
from the constructor rather than promise rejections after calling show(). Removed a bogus
test for applicationData. Cleaned up numerous tests by moving setup code to the correct
location.

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

13 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/ssl/applepay/PaymentRequest.https-expected.txt
LayoutTests/http/tests/ssl/applepay/PaymentRequest.https.html
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/payment-request/w3c-import.log
Source/WebCore/ChangeLog
Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp
Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.h
Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp
Source/WebCore/Modules/paymentrequest/PaymentHandler.h
Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp

index f327af9..c8221cb 100644 (file)
@@ -1,3 +1,17 @@
+2020-01-02  Andy Estes  <aestes@apple.com>
+
+        [Payment Request] Perform payment method data IDL conversion in the PaymentRequest constructor
+        https://bugs.webkit.org/show_bug.cgi?id=199225
+        <rdar://problem/52217847>
+
+        Reviewed by Darin Adler.
+
+        * http/tests/ssl/applepay/PaymentRequest.https-expected.txt:
+        * http/tests/ssl/applepay/PaymentRequest.https.html: Changed some tests to expect exceptions
+        from the constructor rather than promise rejections after calling show(). Removed a bogus
+        test for applicationData. Cleaned up numerous tests by moving setup code to the correct
+        location.
+
 2020-01-02  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Unreviewed test gardening for iPad
index c9c4b0e..719c0ff 100644 (file)
@@ -10,291 +10,322 @@ PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails()) did not t
 
 Testing ApplePayRequest.version
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.version = 0;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with InvalidAccessError: "0" is not a supported version..
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.version = 1000;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with InvalidAccessError: "1000" is not a supported version..
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.version = 0; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with InvalidAccessError: "0" is not a supported version..
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.version = 1000; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with InvalidAccessError: "1000" is not a supported version..
 
 Testing ApplePayRequest.countryCode
 
 SETUP: paymentMethod = validPaymentMethod(); delete paymentMethod.data.countryCode;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.countryCode is required and must be an instance of DOMString.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Member ApplePayRequest.countryCode is required and must be an instance of DOMString.
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 'invalid';
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "invalid" is not a valid country code..
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = '';
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "" is not a valid country code..
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = undefined;
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Member ApplePayRequest.countryCode is required and must be an instance of DOMString.
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = null;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "null" is not a valid country code..
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = undefined;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.countryCode is required and must be an instance of DOMString.
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 'invalid'; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: "invalid" is not a valid country code..
+
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = ''; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: "" is not a valid country code..
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 7;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "7" is not a valid country code..
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = null; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: "null" is not a valid country code..
+
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 7; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: "7" is not a valid country code..
 
 Testing ApplePayRequest.supportedNetworks
 
 SETUP: paymentMethod = validPaymentMethod(); delete paymentMethod.data.supportedNetworks;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.supportedNetworks is required and must be an instance of sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Member ApplePayRequest.supportedNetworks is required and must be an instance of sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = '';
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = null;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = undefined;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.supportedNetworks is required and must be an instance of sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Member ApplePayRequest.supportedNetworks is required and must be an instance of sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = 7;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = [];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: At least one supported network must be provided..
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork'];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "invalidNetwork" is not a valid payment network..
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = []; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: At least one supported network must be provided..
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork', 'visa'];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "invalidNetwork" is not a valid payment network..
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork']; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: "invalidNetwork" is not a valid payment network..
+
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork', 'visa']; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: "invalidNetwork" is not a valid payment network..
 
 Testing ApplePayRequest.merchantCapabilities
 
 SETUP: paymentMethod = validPaymentMethod(); delete paymentMethod.data.merchantCapabilities;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.merchantCapabilities is required and must be an instance of sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Member ApplePayRequest.merchantCapabilities is required and must be an instance of sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = '';
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = null;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = undefined;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.merchantCapabilities is required and must be an instance of sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Member ApplePayRequest.merchantCapabilities is required and must be an instance of sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = 7;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = [];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: At least one merchant capability must be provided..
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = ['invalidCapability'];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = ['invalidCapability', 'supports3DS'];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
+
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = []; request = new PaymentRequest([paymentMethod], validPaymentDetails())
+PASS request.show() rejected promise  with TypeError: At least one merchant capability must be provided..
 
 Testing ApplePayRequest.requiredBillingContactFields
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = '';
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = null;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = 7;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = { };
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [''];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [null];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [undefined];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [{}];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = ['invalid'];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 Testing ApplePayRequest.billingContact
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.billingContact = '';
-PASS new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with InvalidStateError: The object is in an invalid state..
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.billingContact = 7;
-PASS new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with InvalidStateError: The object is in an invalid state..
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 Testing ApplePayRequest.requiredShippingContactFields
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = '';
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = null;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = 7;
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Value is not a sequence.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Value is not a sequence.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = { };
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [''];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [null];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [undefined];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [{}];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = ['invalid'];
-PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Type error.
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
+
 
 Testing ApplePayRequest.shippingContact
 
 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.shippingContact = '';
-PASS new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with InvalidStateError: The object is in an invalid state..
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.shippingContact = 7;
-PASS new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with InvalidStateError: The object is in an invalid state..
 
-Testing ApplePayRequest.applicationData
+SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.shippingContact = 7;
+PASS new PaymentRequest([paymentMethod], validPaymentDetails()) threw exception TypeError: Type error.
 
-SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.applicationData = { toString: function() { throw '"Error in toString"'; } };
-PASS new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with InvalidStateError: The object is in an invalid state..
 
 Testing PaymentDetails.total
 
 SETUP: paymentDetails = validPaymentDetails(); delete paymentDetails.total;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentDetailsInit.total is required and must be an instance of PaymentItem.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentDetailsInit.total is required and must be an instance of PaymentItem.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = '';
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = null;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = undefined;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentDetailsInit.total is required and must be an instance of PaymentItem.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentDetailsInit.total is required and must be an instance of PaymentItem.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = 7;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = [];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = { };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label' };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: 'amount' };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: '', value: '0' } };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception RangeError: "" is not a valid currency code..
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception RangeError: "" is not a valid currency code..
 
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: 'USD', value:'-10.00'} };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Total currency values cannot be negative..
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Total currency values cannot be negative..
 
-SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: 'USD', value: '10000000000.00' } };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() rejected promise  with TypeError: Total amount is too big..
+SETUP: paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: 'USD', value: '10000000000.00' } }; request = new PaymentRequest([validPaymentMethod()], paymentDetails)
+PASS request.show() rejected promise  with TypeError: Total amount is too big..
 
 Testing PaymentDetails.displayItems
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = '';
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Value is not a sequence.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Value is not a sequence.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = null;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Value is not a sequence.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Value is not a sequence.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = 7;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Value is not a sequence.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Value is not a sequence.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = { };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [''];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [null];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [undefined];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{}];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentItem.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '10.00', type: 'invalid' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
-SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: { currency: 'EUR', value: '10.00' } }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() rejected promise  with TypeError: "EUR" does not match the expected currency of "USD". Apple Pay requires all PaymentCurrencyAmounts to use the same currency code..
+SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: { currency: 'EUR', value: '10.00' } }]; request = new PaymentRequest([validPaymentMethod()], paymentDetails)
+PASS request.show() rejected promise  with TypeError: "EUR" does not match the expected currency of "USD". Apple Pay requires all PaymentCurrencyAmounts to use the same currency code..
 Testing PaymentDetails.shippingOptions
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = '';
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Value is not a sequence.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Value is not a sequence.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = 'invalid';
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Value is not a sequence.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Value is not a sequence.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = null;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Value is not a sequence.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Value is not a sequence.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = 7;
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Value is not a sequence.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Value is not a sequence.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = { };
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Member PaymentShippingOption.amount is required and must be an instance of PaymentCurrencyAmount.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Member PaymentShippingOption.amount is required and must be an instance of PaymentCurrencyAmount.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '', identifier: '' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '', identifier: '', label: '' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
 SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '-1', detail: '', identifier: '', label: '' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], paymentDetails) threw exception TypeError: Type error.
 
-SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: { currency: 'EUR', value: '10.00' }, id: '', label: '' }];
-PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() rejected promise  with TypeError: "EUR" does not match the expected currency of "USD". Apple Pay requires all PaymentCurrencyAmounts to use the same currency code..
+SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: { currency: 'EUR', value: '10.00' }, id: '', label: '' }]; request = new PaymentRequest([validPaymentMethod()], paymentDetails)
+PASS request.show() rejected promise  with TypeError: "EUR" does not match the expected currency of "USD". Apple Pay requires all PaymentCurrencyAmounts to use the same currency code..
 Testing PaymentOptions
 
 SETUP: paymentOptions = {}; paymentOptions.shippingType = '';
-PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions) threw exception TypeError: Type error.
 
 SETUP: paymentOptions = {}; paymentOptions.shippingType = 'invalid';
-PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions) threw exception TypeError: Type error.
 
 SETUP: paymentOptions = {}; paymentOptions.shippingType = null;
-PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions) threw exception TypeError: Type error.
 
 SETUP: paymentOptions = {}; paymentOptions.shippingType = 7;
-PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions) threw exception TypeError: Type error.
 
 SETUP: paymentOptions = {}; paymentOptions.shippingType = { };
-PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show() threw exception TypeError: Type error.
+PASS new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions) threw exception TypeError: Type error.
 
 PASS successfullyParsed is true
 
index 9e979e9..4811e31 100644 (file)
@@ -58,178 +58,173 @@ async function go() {
     
     debug("Testing ApplePayRequest.version")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.version = 0;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.version = 1000;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.version = 0; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.version = 1000; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
 
     debug("Testing ApplePayRequest.countryCode")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); delete paymentMethod.data.countryCode;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); delete paymentMethod.data.countryCode;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 'invalid';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = undefined;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = '';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 'invalid'; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = null;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = ''; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = undefined;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = null; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 7;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 7; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
 
     debug("Testing ApplePayRequest.supportedNetworks")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); delete paymentMethod.data.supportedNetworks;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); delete paymentMethod.data.supportedNetworks;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = '';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = '';", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = null;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = null;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = undefined;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = undefined;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = 7;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = [];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = []; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork'];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork']; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork', 'visa'];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.supportedNetworks = ['invalidNetwork', 'visa']; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
 
     debug("Testing ApplePayRequest.merchantCapabilities")
     debug("");
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); delete paymentMethod.data.merchantCapabilities;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); delete paymentMethod.data.merchantCapabilities;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = '';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = '';", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = null;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = null;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = undefined;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = undefined;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = 7;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = [];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = ['invalidCapability'];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = ['invalidCapability'];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = ['invalidCapability', 'supports3DS'];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = ['invalidCapability', 'supports3DS'];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.merchantCapabilities = []; request = new PaymentRequest([paymentMethod], validPaymentDetails())", "request.show()")
     debug("")
 
     debug("Testing ApplePayRequest.requiredBillingContactFields")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = '';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = '';", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = null;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = null;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = 7;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = { };", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = { };", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [''];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [''];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [null];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [null];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [undefined];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [undefined];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [{}];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = [{}];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = ['invalid'];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredBillingContactFields = ['invalid'];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
 
     debug("Testing ApplePayRequest.billingContact")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.billingContact = '';", "new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.billingContact = '';", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.billingContact = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.billingContact = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
 
     debug("Testing ApplePayRequest.requiredShippingContactFields")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = '';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = '';", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = null;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = null;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = 7;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = { };", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = { };", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [''];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [''];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [null];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [null];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [undefined];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [undefined];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [{}];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = [{}];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = ['invalid'];", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.requiredShippingContactFields = ['invalid'];", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
 
     debug("Testing ApplePayRequest.shippingContact")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.shippingContact = '';", "new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.shippingContact = '';", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.shippingContact = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
-    debug("")
-    
-    debug("Testing ApplePayRequest.applicationData")
-    debug("")
-    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.applicationData = { toString: function() { throw '\"Error in toString\"'; } };", "new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
+    await logAndShouldThrow("paymentMethod = validPaymentMethod(); paymentMethod.data.shippingContact = 7;", "new PaymentRequest([paymentMethod], validPaymentDetails())")
     debug("")
 
     debug("Testing PaymentDetails.total")
     debug("")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); delete paymentDetails.total;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = '';", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = null;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = undefined;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = 7;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = [];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label' };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: 'amount' };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: '', value: '0' } };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); delete paymentDetails.total;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = '';", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = null;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = undefined;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = 7;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = [];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { };", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label' };", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: 'amount' };", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: '', value: '0' } };", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
     debug("")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: 'USD', value:'-10.00'} };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: 'USD', value: '10000000000.00' } };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: 'USD', value:'-10.00'} };", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.total = { label: 'label', amount: { currency: 'USD', value: '10000000000.00' } }; request = new PaymentRequest([validPaymentMethod()], paymentDetails)", "request.show()")
     debug("")
 
     debug("Testing PaymentDetails.displayItems")
     debug("");
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = '';", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = null;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = 7;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = { };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [''];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [null];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [undefined];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{}];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '10.00', type: 'invalid' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: { currency: 'EUR', value: '10.00' } }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = '';", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = null;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = 7;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = { };", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [''];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [null];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [undefined];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{}];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label' }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '' }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '10.00', type: 'invalid' }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: { currency: 'EUR', value: '10.00' } }]; request = new PaymentRequest([validPaymentMethod()], paymentDetails)", "request.show()")
 
     debug("Testing PaymentDetails.shippingOptions")
     debug("");
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = '';", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = 'invalid';", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = null;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = 7;", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = { };", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '', identifier: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '', identifier: '', label: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '-1', detail: '', identifier: '', label: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
-    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: { currency: 'EUR', value: '10.00' }, id: '', label: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = '';", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = 'invalid';", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = null;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = 7;", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = { };", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '' }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '', identifier: '' }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '', identifier: '', label: '' }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '-1', detail: '', identifier: '', label: '' }];", "new PaymentRequest([validPaymentMethod()], paymentDetails)")
+    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: { currency: 'EUR', value: '10.00' }, id: '', label: '' }]; request = new PaymentRequest([validPaymentMethod()], paymentDetails)", "request.show()")
 
     debug("Testing PaymentOptions")
     debug("");
-    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = '';", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show()")
-    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = 'invalid';", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show()")
-    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = null;", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show()")
-    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = 7;", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show()")
-    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = { };", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions); request.show()")
+    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = '';", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions)")
+    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = 'invalid';", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions)")
+    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = null;", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions)")
+    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = 7;", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions)")
+    await logAndShouldThrow("paymentOptions = {}; paymentOptions.shippingType = { };", "new PaymentRequest([validPaymentMethod()], validPaymentDetails(), paymentOptions)")
 
     document.querySelector("button").remove();
 
index 5477a93..4f2eebd 100644 (file)
@@ -1,3 +1,18 @@
+2020-01-02  Andy Estes  <aestes@apple.com>
+
+        [Payment Request] Perform payment method data IDL conversion in the PaymentRequest constructor
+        https://bugs.webkit.org/show_bug.cgi?id=199225
+        <rdar://problem/52217847>
+
+        Reviewed by Darin Adler.
+
+        Imported test web-platform-tests/payment-request/constructor_convert_method_data.https.html
+        using Tools/Scripts/import-w3c-tests.
+
+        * web-platform-tests/payment-request/constructor_convert_method_data.https-expected.txt: Added.
+        * web-platform-tests/payment-request/constructor_convert_method_data.https.html: Added.
+        * web-platform-tests/payment-request/w3c-import.log: 
+
 2020-01-01  youenn fablet  <youenn@apple.com>
 
         Implement transceiver setCodecPreferences
diff --git a/LayoutTests/imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https-expected.txt
new file mode 100644 (file)
index 0000000..fcef036
--- /dev/null
@@ -0,0 +1,5 @@
+
+PASS Smoke test. 
+PASS Tries to convert data member during Payment Request construction, irrespective of PMI. 
+PASS Converts PaymentMethodData's data to mandated IDL type during PaymentRequest construction. 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https.html b/LayoutTests/imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https.html
new file mode 100644 (file)
index 0000000..56866b4
--- /dev/null
@@ -0,0 +1,73 @@
+<!DOCTYPE html> <meta charset="utf-8" />
+<title>Validates PaymentMethodData's data member during construction</title>
+<link
+  rel="help"
+  href="https://w3c.github.io/browser-payment-api/#constructor"
+/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  const details = {
+    total: {
+      label: "Total",
+      amount: {
+        currency: "USD",
+        value: "0.00",
+      },
+    },
+  };
+
+  test(() => {
+    new PaymentRequest([{ supportedMethods: "basic-card" }], details);
+    new PaymentRequest(
+      [{ supportedMethods: "https://apple.com/apple-pay" }],
+      details
+    );
+  }, "Smoke test.");
+
+  const knownPMIs = ["basic-card", "https://apple.com/apple-pay"];
+  const unknownPMIs = ["fake-pmi", "https://does-not.exist"];
+
+  promise_test(async t => {
+    for (const supportedMethods of [].concat(knownPMIs).concat(unknownPMIs)) {
+      const method = { supportedMethods };
+      const request = new PaymentRequest([method], details);
+      assert_throws(
+        new TypeError(),
+        () => {
+          const badMethod = Object.assign(
+            {},
+            method,
+            { data: 123 } // <- this will throw
+          );
+          new PaymentRequest([badMethod], details);
+        },
+        "PaymentMethodData.data can't be converted to an Object."
+      );
+    }
+  }, "Tries to convert data member during Payment Request construction, irrespective of PMI.");
+
+  promise_test(async t => {
+    for (const supportedMethods of knownPMIs) {
+      const method = { supportedMethods };
+      const request = new PaymentRequest([method], details);
+
+      // Only check the PMIs that are actually supported
+      if (!(await request.canMakePayment())) continue;
+
+      assert_throws(
+        new TypeError(),
+        () => {
+          const badMethod = Object.assign(
+            {},
+            method,
+            /* This is invalid in both Apple Pay and Basic Card */
+            { data: { supportedNetworks: "this will throw" } }
+          );
+          new PaymentRequest([badMethod], details);
+        },
+        "PaymentMethodData.data is invalid."
+      );
+    }
+  }, "Converts PaymentMethodData's data to mandated IDL type during PaymentRequest construction.");
+</script>
index 7b522b5..badf42c 100644 (file)
@@ -18,6 +18,7 @@ List of files:
 /LayoutTests/imported/w3c/web-platform-tests/payment-request/algorithms-manual.https.html
 /LayoutTests/imported/w3c/web-platform-tests/payment-request/change-shipping-option-manual.https.html
 /LayoutTests/imported/w3c/web-platform-tests/payment-request/change-shipping-option-select-last-manual.https.html
+/LayoutTests/imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https.html
 /LayoutTests/imported/w3c/web-platform-tests/payment-request/historical.https.html
 /LayoutTests/imported/w3c/web-platform-tests/payment-request/idlharness.https.window.js
 /LayoutTests/imported/w3c/web-platform-tests/payment-request/onmerchantvalidation-attribute.https.html
index 0cee1b6..961cbe8 100644 (file)
@@ -1,3 +1,36 @@
+2020-01-02  Andy Estes  <aestes@apple.com>
+
+        [Payment Request] Perform payment method data IDL conversion in the PaymentRequest constructor
+        https://bugs.webkit.org/show_bug.cgi?id=199225
+        <rdar://problem/52217847>
+
+        Reviewed by Darin Adler.
+
+        Implemented support for validating payment method data during Payment Request construction.
+        IDL conversion errors for payment method data will now trigger an exception in the
+        PaymentRequest constructor rather than being deferred to the show() method.
+
+        Payment Request specified this change in <https://github.com/w3c/payment-request/pull/829>.
+
+        Test: imported/w3c/web-platform-tests/payment-request/constructor_convert_method_data.https.html
+
+        * Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp:
+        (WebCore::convertAndValidate): Moved the logic for converting a JSValue to an
+        ApplePayRequest IDL type from ApplePayPaymentHandler::convertData to here.
+        (WebCore::ApplePayPaymentHandler::validateData): Added. Checks that the specified JSValue is
+        a valid ApplePayRequest, throwing an exception if not.
+        (WebCore::ApplePayPaymentHandler::convertData): Changed to use convertAndValidate to convert
+        from a JSValue to an ApplePayRequest.
+        * Modules/applepay/paymentrequest/ApplePayPaymentHandler.h:
+        * Modules/paymentrequest/PaymentHandler.cpp:
+        (WebCore::PaymentHandler::validateData): Added. Calls ApplePayPaymentHandler::validateData
+        if Apple Pay handles the specified identifier.
+        * Modules/paymentrequest/PaymentHandler.h:
+        * Modules/paymentrequest/PaymentRequest.cpp:
+        (WebCore::parse): Moved up to be callable by PaymentRequest::create.
+        (WebCore::PaymentRequest::create): Validated that serializedData can be converted to a valid
+        ApplePayRequest, throwing an exception if not.
+
 2020-01-02  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][Integration] Fix failing text-indent cases when the IFC root is an anonymous box
index 4195c2f..7fa077a 100644 (file)
 
 namespace WebCore {
 
+static ExceptionOr<ApplePayRequest> convertAndValidate(ScriptExecutionContext& context, JSC::JSValue data)
+{
+    if (data.isEmpty())
+        return Exception { TypeError, "Missing payment method data." };
+
+    auto throwScope = DECLARE_THROW_SCOPE(context.vm());
+    auto applePayRequest = convertDictionary<ApplePayRequest>(*context.execState(), data);
+    if (throwScope.exception())
+        return Exception { ExistingExceptionError };
+
+    return WTFMove(applePayRequest);
+}
+
+ExceptionOr<void> ApplePayPaymentHandler::validateData(Document& document, JSC::JSValue data)
+{
+    auto requestOrException = convertAndValidate(document, data);
+    if (requestOrException.hasException())
+        return requestOrException.releaseException();
+
+    return { };
+}
+
 bool ApplePayPaymentHandler::handlesIdentifier(const PaymentRequest::MethodIdentifier& identifier)
 {
     if (!WTF::holds_alternative<URL>(identifier))
@@ -160,18 +182,13 @@ static ExceptionOr<ApplePaySessionPaymentRequest::ShippingMethod> convertAndVali
     return { WTFMove(result) };
 }
 
-ExceptionOr<void> ApplePayPaymentHandler::convertData(JSC::JSValue&& data)
+ExceptionOr<void> ApplePayPaymentHandler::convertData(JSC::JSValue data)
 {
-    if (data.isEmpty())
-        return Exception { TypeError, "Missing payment method data." };
-
-    auto& context = *scriptExecutionContext();
-    auto throwScope = DECLARE_THROW_SCOPE(context.vm());
-    auto applePayRequest = convertDictionary<ApplePayRequest>(*context.execState(), WTFMove(data));
-    if (throwScope.exception())
-        return Exception { ExistingExceptionError };
+    auto requestOrException = convertAndValidate(*scriptExecutionContext(), data);
+    if (requestOrException.hasException())
+        return requestOrException.releaseException();
 
-    m_applePayRequest = WTFMove(applePayRequest);
+    m_applePayRequest = requestOrException.releaseReturnValue();
     return { };
 }
 
index 82b91b6..89c757f 100644 (file)
@@ -42,6 +42,7 @@ class PaymentCoordinator;
 
 class ApplePayPaymentHandler final : public PaymentHandler, public PaymentSession, private ContextDestructionObserver {
 public:
+    static ExceptionOr<void> validateData(Document&, JSC::JSValue);
     static bool handlesIdentifier(const PaymentRequest::MethodIdentifier&);
     static bool hasActiveSession(Document&);
 
@@ -64,7 +65,7 @@ private:
     ExceptionOr<void> paymentMethodUpdated();
 
     // PaymentHandler
-    ExceptionOr<void> convertData(JSC::JSValue&&) final;
+    ExceptionOr<void> convertData(JSC::JSValue) final;
     ExceptionOr<void> show(Document&) final;
     void hide() final;
     void canMakePayment(Document&, WTF::Function<void(bool)>&& completionHandler) final;
index a76d4b4..f55da25 100644 (file)
@@ -61,6 +61,20 @@ ExceptionOr<void> PaymentHandler::canCreateSession(Document& document)
     return { };
 }
 
+ExceptionOr<void> PaymentHandler::validateData(Document& document, JSC::JSValue data, const PaymentRequest::MethodIdentifier& identifier)
+{
+#if ENABLE(APPLE_PAY)
+    if (ApplePayPaymentHandler::handlesIdentifier(identifier))
+        return ApplePayPaymentHandler::validateData(document, data);
+#else
+    UNUSED_PARAM(document);
+    UNUSED_PARAM(data);
+    UNUSED_PARAM(identifier);
+#endif
+
+    return { };
+}
+
 bool PaymentHandler::enabledForContext(ScriptExecutionContext& context)
 {
 #if ENABLE(APPLE_PAY)
index b48ba73..811a285 100644 (file)
@@ -46,10 +46,11 @@ class PaymentHandler : public virtual PaymentSessionBase {
 public:
     static RefPtr<PaymentHandler> create(Document&, PaymentRequest&, const PaymentRequest::MethodIdentifier&);
     static ExceptionOr<void> canCreateSession(Document&);
+    static ExceptionOr<void> validateData(Document&, JSC::JSValue, const PaymentRequest::MethodIdentifier&);
     static bool enabledForContext(ScriptExecutionContext&);
     static bool hasActiveSession(Document&);
 
-    virtual ExceptionOr<void> convertData(JSC::JSValue&&) = 0;
+    virtual ExceptionOr<void> convertData(JSC::JSValue) = 0;
     virtual ExceptionOr<void> show(Document&) = 0;
     virtual void hide() = 0;
     virtual void canMakePayment(Document&, WTF::Function<void(bool)>&& completionHandler) = 0;
index 4c75351..caadf87 100644 (file)
@@ -311,6 +311,15 @@ static ExceptionOr<std::tuple<String, Vector<String>>> checkAndCanonicalizeDetai
     return std::make_tuple(WTFMove(selectedShippingOption), WTFMove(serializedModifierData));
 }
 
+static ExceptionOr<JSC::JSValue> parse(ScriptExecutionContext& context, const String& string)
+{
+    auto scope = DECLARE_THROW_SCOPE(context.vm());
+    JSC::JSValue data = JSONParse(context.execState(), string);
+    if (scope.exception())
+        return Exception { ExistingExceptionError };
+    return data;
+}
+
 // Implements the PaymentRequest Constructor
 // https://www.w3.org/TR/payment-request/#constructor
 ExceptionOr<Ref<PaymentRequest>> PaymentRequest::create(Document& document, Vector<PaymentMethodData>&& methodData, PaymentDetailsInit&& details, PaymentOptions&& options)
@@ -338,6 +347,14 @@ ExceptionOr<Ref<PaymentRequest>> PaymentRequest::create(Document& document, Vect
             serializedData = JSONStringify(document.execState(), paymentMethod.data.get(), 0);
             if (scope.exception())
                 return Exception { ExistingExceptionError };
+            
+            auto parsedDataOrException = parse(document, serializedData);
+            if (parsedDataOrException.hasException())
+                return parsedDataOrException.releaseException();
+            
+            auto exception = PaymentHandler::validateData(document, parsedDataOrException.releaseReturnValue(), *identifier);
+            if (exception.hasException())
+                return exception.releaseException();
         }
         serializedMethodData.uncheckedAppend({ WTFMove(*identifier), WTFMove(serializedData) });
     }
@@ -376,15 +393,6 @@ PaymentRequest::~PaymentRequest()
     ASSERT(!m_activePaymentHandler);
 }
 
-static ExceptionOr<JSC::JSValue> parse(ScriptExecutionContext& context, const String& string)
-{
-    auto scope = DECLARE_THROW_SCOPE(context.vm());
-    JSC::JSValue data = JSONParse(context.execState(), string);
-    if (scope.exception())
-        return Exception { ExistingExceptionError };
-    return WTFMove(data);
-}
-
 // https://www.w3.org/TR/payment-request/#show()-method
 void PaymentRequest::show(Document& document, RefPtr<DOMPromise>&& detailsPromise, ShowPromise&& promise)
 {